作为一名 Cocoa/Obj-C 新手,我正在阅读 Aaron Hillegass 所著的《Mac OS X 的 Cocoa 编程》一书,并且 - 抛开现在我们还有机会使用 GC 来避免所有这些推理这一事实 -我不确定我是否明白其中一些保留的原因。
特别是 Aaron 给出的一个良好编程实践的示例:
- (void) setFoo:(NSCalendarDate *)x
{
[x retain];
[foo release];
foo = x;
}
我不明白在方法的第一行保留 x 实例的原因:
[x retain];
这个实例的作用域只是set方法,对吧? 当退出方法作用域时,x 实例无论如何都应该被释放,不是吗? 此外,当将 x 分配给 foo 时:
foo = x;
foo 无论如何都会指向 x 个内存单元,因此会增加指向的对象保留计数,不是吗?这应该确保内存不会被释放。
所以,有什么意义呢?当然,我确信我错过了一些东西,但不知道到底是什么。
谢谢, 法布里齐奥
最佳答案
Retain 的意思是:我需要保留这个对象,它不能被释放。如果 x
不被保留,则可能会发生以下情况:
您将 x
分配给 foo
,因此 foo
现在指向您的 NSCalendarDate 所在的地址。有人释放或自动释放该对象,它的保留计数最终降至 0,并且该对象被释放。现在您的 foo
仍然指向该地址,但不再是有效的对象。一段时间后,创建一个新对象,并且它碰巧位于与旧 NSCalendarDate 对象相同的地址。现在你的 foo
指向一个完全不同的对象!
为了防止这种情况,您需要保留
它。你需要说,请不要释放该对象,我需要它。一旦你完成它,你释放
它,这意味着我不再需要该对象,如果没有其他人需要它,您现在可以清理它。
现在进行经典的三部分作业。考虑一下您的 setFoo:
看起来像这样:
- (void) setFoo:(NSCalendarDate *)x
{
[foo release];
[x retain];
foo = x;
}
这是一个非常糟糕的主意。考虑您的对象是唯一保留 NSCalendarDate 对象的对象,并考虑您将执行:[self setFoo:foo];
。可能听起来很愚蠢,但这样的事情可能会发生。现在的流程是这样的:
foo
将被释放。它的保留计数现在可能会下降到 0,并且该对象将被释放。- 哎呀,我们正在尝试保留并访问已释放的对象。
这就是为什么您总是首先保留
新对象,然后释放
旧对象。
如果您有 Java 或 .NET 背景,了解 Foo *
类型的变量仅包含对象的地址非常重要,仅此而已。在 Java 或 .NET 中,如果您愿意,指向对象的变量会自动“保留”该对象。在 Objective-C 中并非如此(在非 GC 环境中)。您可以将 Foo *
类型的变量视为弱引用,并且您明确需要告诉 Objective-C 您是否仍需要该地址处的该对象。
关于objective-c - 另一个 "Retain, then Release"问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6213192/