我是编码新手,并试图跟上 Objective-C 的速度。
遇到一些我不明白的代码。我希望有人可以
帮我澄清一下。在下面的情况下,我不确定 *foo2 是如何工作的以及为什么它没有被发布?
ClassOne *pointer = [[ClassOne alloc]init];
ClassTwo *foo = [[ClassTwo alloc]init], *foo2;
foo2 = [foo add: pointer];
[foo release];
foo = foo2
[pointer release];
[foo release];
最佳答案
使用 Objective-C Cocoa,我们正在使用半自动引用计数内存管理。为对象分配内存、保留对象或调用 copy
时对象上的方法,保留计数(引用计数)增加 1。调用时 release
在一个对象上,它将保留计数减一。打电话时autorelease
在一个物体上,release
将在将来的某个时间点在对象上调用(在主运行循环期间,当您自己的代码都没有执行时,因此当您尝试使用它时,它不会从您的下方拉出引用)。当保留计数达到 0 时,可以释放对象。
一般来说,如果您拨打 retain
在一个物体上,你表明你对它感兴趣,你有责任制作 release
或 autorelease
当您不再对对象感兴趣时调用。同样,如果您拨打 alloc
或 copy
对象上的方法,您已经表示您对该对象感兴趣,并且必须将其与 release
匹配或 autorelease
下线的某个地方。
此链接几乎涵盖了 Apple 使用(您应该使用)的内存管理指南:Simple rules for memory management in Cocoa
让我们逐行浏览代码:
ClassOne *pointer = [[ClassOne alloc]init];
pointer
指向一个新分配的 ClassOne 对象,保留计数为 1,因为我们对其调用了 alloc。我们有责任拨打release
或 autorelease
在 pointer
在 future 的某个时候。ClassTwo *foo = [[ClassTwo alloc]init], *foo2;
foo
指向一个新分配的 ClassTwo 对象,保留计数为 1,因为我们对其调用了 alloc。我们有责任拨打release
或 autorelease
在 foo
在 future 的某个时候。foo2
现在没有特别指向任何东西。使用起来并不安全。foo2 = [foo add: pointer];
pointer
已添加到 foo
(不管这意味着什么;我们不知道实现)。 foo
可能打过电话 retain
在 pointer
表明它对它感兴趣,并将其添加为一个字段,或者它可能添加了 pointer
到一个集合(在这种情况下,集合有责任在添加对象时调用 retain
,删除对象时调用 release
)。在任何情况下,它都不会影响我们的代码块,所以我们不关心引擎盖下发生了什么此方法返回的引用可能是
pointer
本身,或者它可能是 pointer
的自动发布副本;我们无权访问 API 或实现来告诉我们哪个。无论哪种情况,我们都没有责任拨打
release
在这个对象上。如果方法有 copy
在名称中,或者如果我们调用 retain
在返回的引用(如 foo2 = [[foo add:pointer] retain];
)上,保留计数将增加 1,我们有责任调用 release
或 autorelease
就可以了。[foo release];
foo
引用的对象已被释放,这意味着它的保留计数已减 1。在本例中,它与 alloc
配对。我们在第 2 行调用,因此保留计数将下降到 0,使 foo
有资格被释放。不过,一般来说,我们并不关心对象是否已被释放;我们只需要确保我们配对任何
alloc
, copy
, 或 retain
与 release
相同号码的调用或 autorelease
调用。如果我们在任何时候注册一个对象的兴趣,释放我们的兴趣是我们的责任,否则我们将有内存泄漏。foo = foo2;
foo
现在指向由 foo2
引用的同一个对象.请记住,我们还没有拨打过 alloc
或 copy
当我们得到 foo2
时的方法,我们也没有通过拨打 retain
来登记对它的兴趣。 .由于我们没有责任拨打release
在 foo2
,我们没有责任拨打release
在 foo
.[pointer release];
pointer
的保留计数已减 1。这可能使其保留计数为 0 或不为 0,这取决于 foo
当我们添加它时就这样做了。不过,我们不在乎;我们已经完成了对pointer
的责任调用 release
就可以与alloc
相匹配我们一开始打的电话。虽然 pointer
在这个调用之后可能仍然存在,我们不能做出这个假设,并且试图对之前由指针引用的对象做任何事情都是错误的(尽管我们可以改变 pointer
以自由地指向其他东西)。[foo release];
如果这段代码的作者一直遵循 Apple 的内存管理约定,那么这是不必要的。我们没有责任拨打
release
在 foo
或 foo2
(它们指向同一个对象,记住)。这不会导致代码中断;在 nil
上调用任何东西引用本质上是一个空操作。但是,它可能会导致任何查看代码的人感到困惑。现在,这段代码的作者可能已经打破了内存管理约定。他可能已经做到了
add
调用返回 pointer
的副本无需调用 autorelease
在它上面,在这种情况下,它让调用者负责调用 release
就可以了。这是非常糟糕的形式,如果您遇到违反内存管理约定的代码,请记录您使用它的位置以及它如何违反约定以避免将来混淆。
关于Objective-C 指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/529482/