以下代码摘自“iOS 5 Developer's Cookbook”,用于说明如何将字符串写入文件。它使用了__autoreleasing而没有任何解释。为什么有必要?
NSError __autoreleasing error;
...
if (![myString writeToFile:path atomically:YES error:&error)
{
NSLog(.... error.localizedFailureReason ...);
return;
}
为什么不在不使用__autoreleasing的情况下在堆栈上声明错误?
------编辑-----
附加问题:为什么作者声明NSError而不是NSError *?
答案 0 :(得分:7)
当一个变量通过引用传递并在ARC程序中分配时,您错过了此代码中实际发生的情况。例如,一个函数(BOOL)保存:(NSError * __autoreleasing *)错误
在非ARC编程中,保存功能如下所示:
- (BOOL)save:(NSError * __autoreleasing *)myError {
*myError = [[[NSError error] retain] autorelease]
}
在ARC编程中,保存功能如下所示:
- (BOOL)save:(NSError * __autoreleasing *)myError {
*myError = [[NSError alloc] init];
}
尽管ARC代码看起来如此,但两个保存函数都会创建一个已保留并自动释放的错误对象。
这是因为在ARC版本中,myError指针的类型决定了错误对象的内存管理会发生什么。实际上,只要指针是__autoreleasing类型,* myError赋值行被替换并带有
*myError = [[[NSError error] retain] autorelease]
在运行时。
因此,如果我们能以某种方式将错误类型的指针传递给保存函数,例如__strong,则会导致save函数执行错误操作。
由于编译器会通过创建临时变量来防止这种情况发生,因此代码将以任何一种方式工作,但是从ARC编程的角度来看,传入一个非__autoreleasing类型的指针是没有意义的。
答案 1 :(得分:3)
它提示自动参考计数(ARC)系统。
error
对象将在NSString的代码中的某处分配,因此在代码中将其声明为__autoreleasing
,ARC可以知道存储特性是什么。也就是说,当设置error
时,它将是一个自动释放的对象。
答案 2 :(得分:2)
__ autoreleasing用于表示通过引用(id *)传递的参数,并在返回时自动释放。
当你声明变量时会产生__strong的隐式声明,但由于它是通过引用传递的,所以编译器需要提示才能做正确的事情。它是否是堆栈变量不会影响保留/释放跟踪。
答案 3 :(得分:1)
代码:
__autoreleasing NSString *str = xx;
将由ARC编译为:
NSString *str = xx.autorelease
答案 4 :(得分:0)
嗯,对于通过引用传递的对象,使用__autoreleasing限定符是一种ARC约定。解释来自clang网站:
4.3.2。 __autoreleasing对象的存储持续时间
如果程序声明__autoreleasing对象,则该程序格式错误 非自动存储时间。
基本原理:自动释放池与当前线程和范围相关联 就其性质而言。虽然有可能有临时对象 实例变量用自动释放的对象填充,没有 ARC可以在那里提供任何形式的安全保障。
如果为a分配了非空指针,则为未定义的行为 __autoreleasing对象,而自动释放池在范围内,然后在自动释放池的范围被删除后读取该对象。