2

作为一个 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 个内存单元,因此会增加指向的对象保留计数,不是吗?这应该确保内存不会被释放。

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

谢谢,法布里齐奥

4

1 回答 1

12

保留意味着:我将需要这个对象留下来,它不能被释放。如果x不保留,可能会发生以下情况:

您分配xfoo,所以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. 哎呀,我们正在尝试保留和访问已释放的对象。

这就是为什么你总是首先retain是新对象,然后release是旧对象。

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

于 2011-06-02T10:31:30.327 回答