NSArray:lastObject返回一个自动释放的对象吗?

9

我正在开发一个iPhone项目,需要从NSMutableArray中检索一个对象,将该对象从数组中删除,然后稍后使用它。 代码大致如下:

NSMutableArray * array;
// fill the array
NSObject * obj = [array lastObject];
[array removeLastObject];
// do something with obj (in the same function)

数组是唯一具有对被访问对象的保留(retain)的实体。这样做安全吗?我认为只有当lastObject自动释放了该对象时,才能起作用,但我无法确定是否是这样。

3个回答

11
为什么不打电话
[array removeLastObject]

你希望在函数结尾处省略一个release/retain。这样可以使你的代码更易读/不那么混乱。

根据苹果文档:

与NSArray一样,NSMutableArray实例会对它们的内容保持强引用。如果您不使用垃圾回收,在将对象添加到数组时,该对象将接收到一个保留消息。当从可变数组中删除对象时,它将接收到一个释放消息。如果没有对该对象进行进一步的引用,则意味着该对象已被释放。如果您的程序保留了这样一个对象的引用,除非在将其从数组中删除之前向该对象发送一个保留消息,否则该引用将变为无效。例如,如果在删除anObject之前未对其进行保留,则下面的第三个语句可能会导致运行时错误:

id anObject = [[anArray objectAtIndex:0] retain]; 
[anArray removeObjectAtIndex:0]; 
[anObject someMessage];

为了让这个结果更加清晰:NSArray和NSMutableArray类对于方法名不包含"new"、"copy"或"alloc"的返回对象有一些例外,它们会返回自动释放的对象。这意味着原始问题中的代码是不安全的。 - harms
@harms 这个规则只适用于对象创建吧? - sylvanaar
4
没有通用的规则表明,从方法中返回的对象如果其名称不包含 "new"、"copy" 或 "alloc",则会返回自动释放的对象。唯一的规则是你不拥有这样的对象。 - JeremyP
@sylvanaar 不,这个规则是普遍适用的,但它的一个结果是授予所有权的方法通常是创建方法,当然还有retain - harms
1
@JeremyP 和 @Nikolai Ruhe:我现在重新阅读了Cocoa内存管理规则,我是对的。请查看“共享对象的有效性”部分。它指出:“Cocoa的所有权策略指定接收到的对象通常应该在调用方法的范围内保持有效。”它继续说:“有时会有例外[...]当一个对象被从基本集合类之一中移除时,它会收到一个释放消息(而不是自动释放)。” - harms

3
值得一提的是Cocoa Memory Management Rules。如果你在非GC环境中工作,比如iPhone,提及它们总是值得的。
基本规则如下:
您使用以“alloc”或“new”开头或包含“copy”的方法(例如,alloc、newObject或mutableCopy)创建对象,或者向其发送retain消息,则拥有该对象的所有权。您负责使用release或autorelease放弃您拥有的对象的所有权。任何其他时间您接收到一个对象,都不应该释放它。
显然,您没有使用alloc、new或包含copy的方法获取obj。所以你不拥有它。
在您的代码中,第二个推论也相关。
收到的对象通常在接收它的方法中保持有效(例外情况包括多线程应用程序和某些分布式对象情况,但如果您修改了从中接收另一个对象的对象,则还必须小心)。该方法也可以安全地将对象返回给调用方。
我已经加粗了相关部分。您已经修改了从中接收对象的数组,因此它可能会消失。您可以在从数组中删除对象之前保留该对象,或者在使用完对象后再进行删除。
实际上,即使是您问题中的代码,您也可能是安全的,因为NSMutableArray的objectAtIndex:的实现可能对返回项执行保留,然后是自动释放。在多线程环境中,这将是确保对象保持足够长时间以将其返回给调用者的唯一方法。但是,我没有看过NSMutableArray的代码,因此不要依赖它。
预计时间:刚刚查看了线程编程指南,似乎NSMutableAtrray不执行保留、自动释放。

谢谢你的回答,最后一行非常有用。 - Chris

2
NSObject * obj = [array lastObject]; // Just returns an object, its retain count not changed
[array removeLastObject]; // object receives release message

如果你的数组是唯一保留你的对象的实体,那么在移除它之后,它的保留计数变为零并且应该被释放。为了安全地使用该对象,你应该保留它并在不需要时释放:

NSObject * obj = [[array lastObject] retain];
[array removeLastObject];
// do something with obj (in the same function)
[obj release];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接