提问人:Wang.Ying 提问时间:2/4/2022 更新时间:4/4/2022 访问量:127
如何创建自动释放对象
how to create an autorelease object
问:
此方法是否创建自动释放对象?
- (instancetype)autoreleasePerson {
return [[Person alloc] init];
}
我创建了一个命令行工具项目来测试这一点:
int main(int argc, const char * argv[]) {
@autoreleasepool {
{
[Person autoreleasePerson];
}
NSLog(@"did out scope");
NSLog(@"will out autoreleasepool");
}
NSLog(@"did out autoreleasepool");
return 0;
}
输出为:
2022-02-04 23:22:23.224298+0800 MyTest[8921:4007144] did out scope
2022-02-04 23:22:23.224771+0800 MyTest[8921:4007144] will out autoreleasepool
2022-02-04 23:22:23.224876+0800 MyTest[8921:4007144] -[Person dealloc]
2022-02-04 23:22:23.224948+0800 MyTest[8921:4007144] did out autoreleasepool
当 autoreleasepool 耗尽时,person 实例将解除锁定!
但是当我在我的 iOS APP 项目中使用相同的 Person 类时:
- (void)viewDidLoad {
[super viewDidLoad];
{
[Person autoreleasePerson];
}
NSLog(@"out scope");
}
输出为:
2022-02-04 23:28:13.992969+0800 MyAppTest[9023:4011490] -[Person dealloc] <Person: 0x600001fe8ff0>
2022-02-04 23:28:13.993075+0800 MyAppTest[9023:4011490] out scope
person 实例在范围外释放一次!
为什么会这样?
答:
在macOS上,默认行为是自动释放返回值,但方法名称以“new”、“init”或“copy”开头的情况除外:
+ (Person *)createPerson {
return [Person new]; // autorelease & return
}
+ (Person *)newPerson {
return [Person new]; // direct return
}
若要控制此行为,请应用编译器属性:
+ (Person *)createPerson __attribute__((ns_returns_retained)) {
return [Person new]; // direct return
}
+ (Person *)newPerson __attribute__((ns_returns_not_retained)) {
return [Person new]; // autorelease & return
}
若要检查编译器是否添加了对 objc_autoreleaseReturnValue 的调用,请启用 Debug -> Debug Workflow -> Always Show Disassembly, 并在这些方法中的返回行上放置一个断点。然后,对 objc_autoreleaseReturnValue 的调用应该可见:
评论
libobjc.A.dylib`objc_unsafeClaimAutoreleasedReturnValue:
这两个结果都是有效的。永远不要假设 ARC 中有自动释放。请参阅 ARC 规范中的“未保留的返回值”部分:
返回可保留对象类型但返回的方法或函数 不返回保留值必须确保对象仍然有效 跨越返回边界。
从此类函数或方法返回时,ARC 会保留该值 在计算 return 语句时,然后保留所有 本地范围,然后平衡保留,同时确保 值存在于调用边界上。在最坏的情况下,这可能 涉及自动释放,但调用方不得假定该值为 实际上在自动释放池中。
所以也许它是自动发布的,也许不是(即也许 ARC 会优化它)。
在这里,ARC 在返回 时会调用 objc_autoreleaseReturnValue(),
因为返回的是保留的引用,但返回的是非保留的引用。的作用是检查返回的结果是否会在调用函数帧中传递给。如果是这样,它可以跳过被调用函数中的自动释放和调用函数中的保留(因为它们“抵消”),并将所有权直接移交给调用函数中保留的引用。autoreleasePerson
+alloc
autoreleasePerson
objc_autoreleaseReturnValue()
objc_retainAutoreleasedReturnValue()
当 ARC
将保留函数调用的结果时,将调用 objc_retainAutoreleasedReturnValue()。现在,我不知道为什么在这种情况下调用会涉及结果的保留,因为结果未使用。也许编译器将其视为 ,因此保留然后释放它。这似乎没有必要,但 ARC 这样做是有效的。如果 ARC 确实碰巧在内部以这种方式处理它,那么上面描述的优化可以跳过自动释放和保留,它将在调用函数中简单地释放。也许它是在你的一个案例中这样做的,而不是在另一个案例中这样做的。谁知道为什么?但我的观点是,两者都是有效的。[Person autoreleasePerson];
Person temp = [Person autoreleasePerson];
有关更详细的说明,请参阅此文章。
评论