方法返回的对象会被放入自动释放池吗?

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)不以表示保留返回类型的特殊名称之一(例如allocretainnewcopymutableCopy)开头,所以它返回非保留参考。 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,从而删除autoreleaseretain,从而取消。在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 *)。

【讨论】:

以上是关于方法返回的对象会被放入自动释放池吗?的主要内容,如果未能解决你的问题,请参考以下文章

ios自动释放池

iOS---NSAutoreleasePool自动释放原理及详解

iOS自动释放池_原理_如何工作

iOS自动释放池_原理_如何工作

0c-36-自动释放池应用场景

Iphone 打开 gl es 应用程序和自动释放池