为什么我们在使用 Quartz API 时必须释放对象?

Why do we have to release objects when using Quartz API?

我最近一直在学习如何在 iOS 开发中使用 Quartz API,并且注意到一些有点奇怪的事情。对于1,为什么我们必须在创建之后释放某些对象?另外,指针变量没有星号,这是为什么呢?像下面的代码:

CGContextRef context = UIGraphicsGetCurrentContext();

在上面的例子中,变量context是一个指针。我们为什么不使用星号?感谢任何 help/guidance。请尽可能详尽,因为我喜欢对我使用的技术有深刻的了解。

您正在处理 C 级 API(未写入或包装在 Objective-C 中)。 CGContextRef 是指向 struct 的指针的 typedef(C 没有 class,但 structs 是容器类型)。查看 CGContext.hCGContextRef 的定义,您会看到那里使用的星号语法。

我能想到 Apple 定义 CGContextRef 而不是让程序员直接使用指向 CGContext 结构的指针的一个主要原因。在 Objective-C 中,您总是在使用指针。您永远不会使用静态分配的 Objective-C class 实例——事实上,编译器禁止这样做。然而,在 C 中,这不是真的。 Apple 希望将所有对 CGContext 结构的引用保留为指针,以便引用计数按预期工作,并且他们可以保证您使用的对象与他们给您的对象相同。旁注:引用计数本身不是 C 语言的一部分,它是 Apple 写入结构的东西,如 CGContext 允许使用它们进行编程感觉类似于使用 Objective-C 对象进行编程。将以下代码片段视为我正在谈论的内容的简洁示例。

在 C 中(您可以将其编译为 Objective-C 程序的一部分):

typedef struct {int a; int b; int refCount;} SimpleObject;

SimpleObject *obj1 = malloc(sizeof(SimpleObject));
obj1->a = 5;
obj1->b = 6;
obj1->refCount = 1;

SimpleObject *obj2 = obj1;

NSLog(@"test: (%d, %d) (%d, %d) (%d, %d)", obj1->a, obj2->a, obj1->b, obj2->b, obj1->refCount, obj2->refCount);
NSLog(@"test: %d", obj1 == obj2); //they are literally the same object (same location in memory)

SimpleObject obj3 = *obj1;

NSLog(@"test: (%d, %d) (%d, %d) (%d, %d)", obj1->a, obj3.a, obj1->b, obj3.b, obj1->refCount, obj3.refCount);
NSLog(@"test: %d", obj1 == &obj3); //they are not the same object (same location in memory)

obj1->refCount--;

NSLog(@"test: how many retains on obj1? %d  how about obj2? %d  and obj3? %d", obj1->refCount, obj2->refCount, obj3.refCount);

free(obj1);

在 Objective-C 中尝试类似的操作,编译器很快就会抛出错误:

NSObject *obj1 = [[NSObject alloc] init];

NSObject *obj2 = obj1;

NSLog(@"test: %d", obj1 == obj2); // they are literally the same object (same location in memory)

NSObject obj3 = obj1; // compiler error

自动引用计数 (ARC) 允许您在 Objective-C 中分配内存,而不必担心稍后释放或取消分配它。这是一个编译器功能,仅对 Obj-C 对象进行操作,因此必须显式释放此和其他 C 级别 API 分配的内存。