方法返回的对象会被放入自动释放池吗?
Posted
技术标签:
【中文标题】方法返回的对象会被放入自动释放池吗?【英文标题】:Will an object returned by a method be put into autorelease pool? 【发布时间】:2015-09-10 16:00:47 【问题描述】:启用ARC后,o
会被放入这段代码sn-p中的自动释放池吗?
- (NSObject *)obj
NSObject *o = [[NSObject alloc] init];
return o;
还有,这两个代码sn-ps有什么区别?
- (NSObject *)obj
NSObject * __autoreleasing o = [[NSObject alloc] init];
return o;
对比
- (NSObject *)obj
NSObject * __strong o = [[NSObject alloc] init];
return o;
【问题讨论】:
回答你第一个问题:是的。只是不在乎。 【参考方案1】:启用 ARC 后,将不会在此代码中放入自动释放池 sn-p?
答案是,可以,也可以不。 ARC 不做任何保证。这里方法的名称(obj
)不以表示保留返回类型的特殊名称之一(例如alloc
、retain
、new
、copy
、mutableCopy
)开头,所以它返回非保留参考。 ARC specification section on "Unretained return values" 说:
在最坏的情况下,这可能涉及自动释放,但调用者必须 不要假设该值实际上在自动释放池中。
在过去,在 MRC 下,您必须在这种情况下执行 autorelease
它才能返回,因为该方法需要返回非保留引用,但必须有人持有对该对象的强引用或否则它将被释放。由于对象是在您的方法中创建的,因此没有其他人对它有引用,并且该方法必须在其作用域结束时摆脱其强引用,因为它不能返回保留引用,所以唯一的方法是让自动释放池在整个回报中具有很强的参考价值。
ARC 必须与 MRC 保持 ABI 兼容(即,您应该能够用 ARC 替换 MRC 实现,反之亦然,而无需更改标头,并且调用者不需要知道它是使用 ARC 编译还是使用 MRC 编译即可工作正确)。因此,在从 MRC 代码调用你的方法的情况下,遵循与上一段相同的逻辑,你的方法必须autorelease
;根本没有其他办法。
但是,ARC 引入了一种巧妙的可选运行时优化,在某些情况下,当调用者和被调用者都使用 ARC 编译时,它可以消除 autorelease
,而调用者或被调用者不需要了解另一方。这大概是它的工作原理:在函数的返回中,通常是autorelease
,ARC 改为调用objc_autoreleaseReturnValue()
。在调用函数并保留返回值的代码中,它改为调用objc_retainAutoreleasedReturnValue()
。在objc_autoreleaseReturnValue()
中,它在堆栈帧上方查看返回地址,以查看返回值是否将传递给objc_retainAutoreleasedReturnValue()
。如果没有,它将autorelease
。如果是,那么它将跳过autorelease
,并修改返回地址以跳过objc_retainAutoreleasedReturnValue
,从而删除autorelease
和retain
,从而取消。在objc_retainAutoreleasedReturnValue()
中,如果没有被跳过,它将只是retain
。这适用于 MRC 到 ARC 调用、ARC 到 ARC 调用和 ARC 到 MRC 调用,并且将消除某些 ARC 到 ARC 调用的autorelease
。
还有,这两个代码sn-ps有什么区别?
第一个会将其放入自动释放池中,而第二个可能不会。 (顺便说一下__strong
是默认的,所以第三段代码和第一段是一样的)
但本质上没有充分的理由使用__autoreleasing
作为局部变量而不是默认值(即__strong
); __strong
更简单,更容易思考。
通常你会遇到__autoreleasing
的唯一一次是在参数中的“指向”类型——如果一个函数声明它需要一个指向__autoreleasing
的指针(例如NSObject * __autoreleasing *
),这意味着它会写以不同于指向__strong
(例如NSObject * __strong *
)的指针的方式指向指向的变量。两种方式都可以,但是调用者和被调用者需要就哪一种达成一致。由于在 Cocoa 中普遍使用NSError * __autoreleasing *
,所以一个不合格的默认指向__autoreleasing
的指针(例如NSObject **
表示NSObject * __autoreleasing *
)。
【讨论】:
以上是关于方法返回的对象会被放入自动释放池吗?的主要内容,如果未能解决你的问题,请参考以下文章