方法返回的对象会被放入自动释放池吗?
Will an object returned by a method be put into autorelease pool?
启用 ARC 后,o
是否会在此代码段中放入自动释放池?
- (NSObject *)obj {
NSObject *o = [[NSObject alloc] init];
return o;
}
另外,这两个代码片段有什么区别?
- (NSObject *)obj {
NSObject * __autoreleasing o = [[NSObject alloc] init];
return o;
}
对比
- (NSObject *)obj {
NSObject * __strong o = [[NSObject alloc] init];
return o;
}
When ARC is enabled, will o be put into autorelease pool in this code
snippet?
答案是,可能会,也可能不会。 ARC 不以任何一种方式做出保证。这里方法的名称 (obj
) 不以指示保留的 return 类型的特殊名称之一开头(例如 alloc
、retain
、new
、 copy
、mutableCopy
),所以它 return 是 non-retained 参考。 ARC specification section on "Unretained return values" 表示:
In the worst case, this may involve an autorelease, but callers must
not assume that the value is actually in the autorelease pool.
在过去,在 MRC 下,在这种情况下,您必须在 return 之前执行 autorelease
,因为该方法需要 return a non-retained 引用,但必须有人持有对 object 的强引用,否则它将被释放。由于 object 是在您的方法中创建的,因此没有其他人引用它,并且该方法必须在其范围末尾摆脱其强引用,因为它不能 return 保留引用,所以唯一的方法是让自动释放池在 return.
中保持强引用
ARC 必须保留 ABI-compatible 和 MRC(即您应该能够用 ARC 替换 MRC 实现,反之亦然,而无需更改 headers 并且调用者不需要知道它是否使用 ARC 或 MRC 编译才能正常工作)。因此,在从 MRC 代码调用您的方法的情况下,遵循与上一段相同的逻辑,您的方法必须 autorelease
;没有其他方法可以做到这一点。
然而,ARC 引入了一个巧妙的可选运行时优化,可以在某些情况下消除 autorelease
当调用者和被调用者都使用 ARC 编译时,调用者或被调用者不需要了解另一方。它大致是这样工作的:在函数的 return 中,您通常会 autorelease
,ARC 却调用 objc_autoreleaseReturnValue()
。在调用函数并保留 return 值的代码中,它调用了 objc_retainAutoreleasedReturnValue()
。在 objc_autoreleaseReturnValue()
中,它查看堆栈帧中的 return 地址以查看 returned 值是否将传递给 objc_retainAutoreleasedReturnValue()
。如果没有,它将 autorelease
。如果是,那么它将跳过 autorelease
,并修改 return 地址以跳过 objc_retainAutoreleasedReturnValue
,从而同时删除 autorelease
和 retain
,抵消了。在objc_retainAutoreleasedReturnValue()
中,如果不跳过,就直接retain
。这适用于 MRC-to-ARC 调用、ARC-to-ARC 调用和 ARC-to-MRC 调用,并且会消除某些 ARC-to-ARC 调用的 autorelease
。
What's more, what is the difference between these two code snippets?
第一个会将其放入自动释放池,而第二个可能不会。 (顺便说一下,__strong
是默认值,所以第三段代码与第一段代码相同。)
但基本上没有充分的理由将 __autoreleasing
用于局部变量而不是默认值(即 __strong
); __strong
只是更简单,更容易思考。
通常你唯一会遇到 __autoreleasing
的情况是在 "pointer-to" 类型的参数中——如果一个函数声明它需要一个指向 __autoreleasing
的指针(例如 NSObject * __autoreleasing *
),这意味着它将以不同于使用指向 __strong
的指针(例如 NSObject * __strong *
)的方式写入 pointed-to 变量。两种方式都有效,但调用者和被调用者需要就哪一种方式达成一致。由于 Cocoa 中 NSError * __autoreleasing *
的普遍使用,不合格的指针默认指向 __autoreleasing
(例如 NSObject **
表示 NSObject * __autoreleasing *
)。
启用 ARC 后,o
是否会在此代码段中放入自动释放池?
- (NSObject *)obj {
NSObject *o = [[NSObject alloc] init];
return o;
}
另外,这两个代码片段有什么区别?
- (NSObject *)obj {
NSObject * __autoreleasing o = [[NSObject alloc] init];
return o;
}
对比
- (NSObject *)obj {
NSObject * __strong o = [[NSObject alloc] init];
return o;
}
When ARC is enabled, will o be put into autorelease pool in this code snippet?
答案是,可能会,也可能不会。 ARC 不以任何一种方式做出保证。这里方法的名称 (obj
) 不以指示保留的 return 类型的特殊名称之一开头(例如 alloc
、retain
、new
、 copy
、mutableCopy
),所以它 return 是 non-retained 参考。 ARC specification section on "Unretained return values" 表示:
In the worst case, this may involve an autorelease, but callers must not assume that the value is actually in the autorelease pool.
在过去,在 MRC 下,在这种情况下,您必须在 return 之前执行 autorelease
,因为该方法需要 return a non-retained 引用,但必须有人持有对 object 的强引用,否则它将被释放。由于 object 是在您的方法中创建的,因此没有其他人引用它,并且该方法必须在其范围末尾摆脱其强引用,因为它不能 return 保留引用,所以唯一的方法是让自动释放池在 return.
ARC 必须保留 ABI-compatible 和 MRC(即您应该能够用 ARC 替换 MRC 实现,反之亦然,而无需更改 headers 并且调用者不需要知道它是否使用 ARC 或 MRC 编译才能正常工作)。因此,在从 MRC 代码调用您的方法的情况下,遵循与上一段相同的逻辑,您的方法必须 autorelease
;没有其他方法可以做到这一点。
然而,ARC 引入了一个巧妙的可选运行时优化,可以在某些情况下消除 autorelease
当调用者和被调用者都使用 ARC 编译时,调用者或被调用者不需要了解另一方。它大致是这样工作的:在函数的 return 中,您通常会 autorelease
,ARC 却调用 objc_autoreleaseReturnValue()
。在调用函数并保留 return 值的代码中,它调用了 objc_retainAutoreleasedReturnValue()
。在 objc_autoreleaseReturnValue()
中,它查看堆栈帧中的 return 地址以查看 returned 值是否将传递给 objc_retainAutoreleasedReturnValue()
。如果没有,它将 autorelease
。如果是,那么它将跳过 autorelease
,并修改 return 地址以跳过 objc_retainAutoreleasedReturnValue
,从而同时删除 autorelease
和 retain
,抵消了。在objc_retainAutoreleasedReturnValue()
中,如果不跳过,就直接retain
。这适用于 MRC-to-ARC 调用、ARC-to-ARC 调用和 ARC-to-MRC 调用,并且会消除某些 ARC-to-ARC 调用的 autorelease
。
What's more, what is the difference between these two code snippets?
第一个会将其放入自动释放池,而第二个可能不会。 (顺便说一下,__strong
是默认值,所以第三段代码与第一段代码相同。)
但基本上没有充分的理由将 __autoreleasing
用于局部变量而不是默认值(即 __strong
); __strong
只是更简单,更容易思考。
通常你唯一会遇到 __autoreleasing
的情况是在 "pointer-to" 类型的参数中——如果一个函数声明它需要一个指向 __autoreleasing
的指针(例如 NSObject * __autoreleasing *
),这意味着它将以不同于使用指向 __strong
的指针(例如 NSObject * __strong *
)的方式写入 pointed-to 变量。两种方式都有效,但调用者和被调用者需要就哪一种方式达成一致。由于 Cocoa 中 NSError * __autoreleasing *
的普遍使用,不合格的指针默认指向 __autoreleasing
(例如 NSObject **
表示 NSObject * __autoreleasing *
)。