另一个“保留,然后释放”的问题

时间:2011-06-02 10:17:50

标签: objective-c cocoa memory-management retaincount

成为Cocoa / Obj-C新手我正在阅读Aaron Hillegass的“Cocoa Programming for Mac OS X”一书,并且 - 现在我们还有机会使用GC避免所有这些推理 - 我不确定我是否得到了其中一些保留的原因。

特别是在其中一个例子中,Aaron提供了良好的编程实践:

- (void) setFoo:(NSCalendarDate *)x
{
    [x retain];
    [foo release];
    foo = x;
}

我没有理由在方法的第一行保留x实例:

[x retain];

这个实例的范围只是set方法,对吧? 当退出方法范围时,x实例应该被解除分配吗? 此外,在将x分配给foo时:

foo = x;

foo无论如何指向x内存单元格,因此会增加指向对象的保留计数,不是吗?这应该确保不会释放内存。

那么,有什么意义呢?当然,我确信我错过了什么,但不知道到底是什么。

谢谢, 的Fabrizio

1 个答案:

答案 0 :(得分:11)

保留意味着:我将需要此对象保持不变,不得取消分配。如果不保留x,则可能发生以下情况:

您将x分配给foo,因此foo现在指向您的NSCalendarDate所在的地址。有人释放或自动释放此对象,它的保留计数最终会降为0并且对象被取消分配。现在您的foo仍指向该地址,但不再是有效对象。稍后,会创建一个新对象,并且它与旧的NSCalendarDate对象位于同一地址。现在你的foo指向一个完全不同的对象!

为了防止这种情况,您需要retain它。你需要说,请不要释放对象,我需要它。一旦你完成了它,你release就意味着我不再需要这个对象了,如果没有其他人需要,你可以立即清理它。

现在为经典的三部分作业。考虑一下您的setFoo:将如下所示:

- (void) setFoo:(NSCalendarDate *)x
{
    [foo release];
    [x retain];
    foo = x;
}

这是一个非常糟糕的主意。考虑您的对象是唯一保留NSCalendarDate对象的对象,并考虑您将执行:[self setFoo:foo];。可能听起来很傻,但这样的事情可能会发生。流程现在是这样的:

  1. foo将被释放。它的保留计数现在可能会降至0并且对象将被释放。
  2. 哎呀,我们试图保留并访问一个已解除分配的对象。
  3. 这就是为什么你总是先retain新对象,然后release旧对象。

    如果您来自Java或.NET背景,了解类型Foo *的变量仅包含对象的地址非常重要,仅此而已。在Java或.NET中,如果愿意,指向对象的变量会自动“保留”它。 Objective-C不是这样(在非GC环境中)。您可以将Foo *类型的变量视为弱引用,并且明确需要告诉Objective-C您是否仍然需要该地址处的该对象。