在代码片段示例中使用__autoreleasing

以下代码摘自“iOS 5 Developer's Cookbook”,用于说明如何将string写入文件。 它利用__autoreleasing没有任何解释。 为什么有必要?

NSError __autoreleasing error; ... if (![myString writeToFile:path atomically:YES error:&error) { NSLog(.... error.localizedFailureReason ...); return; } 

为什么不直接声明栈上的错误而不使用__autoreleasing?

——编辑—–

附加问题:为什么作者声明NSError而不是NSError *?

这是自动引用计数(ARC)系统的一个提示。

error对象将被分配在NSString代码的某处,所以在你的代码中声明它为__autoreleasing让ARC知道存储特性是什么。 也就是说,当error被设置时,它将是一个自动释放的对象。

当一个variables通过引用传递并分配给一个ARC程序时,你错过了这段代码中实际发生的事情。 以一个函数(BOOL)保存为例:(NSError * __autoreleasing *)错误

在非ARC编程中,保存function如下所示:

 - (BOOL)save:(NSError * __autoreleasing *)myError { *myError = [[[NSError error] retain] autorelease] } 

在ARC编程中,保存function如下所示:

 - (BOOL)save:(NSError * __autoreleasing *)myError { *myError = [[NSError alloc] init]; } 

尽pipeARC代码看起来像,两个保存函数都会创build一个已被保留和自动释放的错误对象。

这是因为在ARC版本中,myError指针的types决定了错误对象的内存pipe理会发生什么情况。 实际上,只要指针的types是__autoreleasing,* myError赋值行就被replace成了

 *myError = [[[NSError error] retain] autorelease] 

在运行时。

所以如果我们不知何故能够传入一个错误types的指针,例如__strong到保存函数,它会导致保存function做错误的事情。

由于编译器会通过创build一个临时variables来防止这种情况的发生,代码将以任何方式工作,但传递一个非__autoreleasingtypes的指针从ARC编程的angular度来看是没有意义的。

从ARC发行说明: https : //developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html :

__autoreleasing用于表示通过引用(id *)传递的参数,并在返回时自动释放。

在声明variables的时候有一个隐含的__strong声明,但是由于它是通过引用传递的,所以编译器需要提示才能做正确的事情。 它是否是堆栈variables不会影响保留/释放跟踪。

代码 :

 __autoreleasing NSString *str = xx; 

将由ARC编译为:

 NSString *str = xx.autorelease 

那么,对于通过引用传递的对象,使用__autoreleasing限定符是一个ARC约定。 这个解释来自clang站点:

4.3.2。 __autoreleasing对象的存储时间

如果一个程序声明了一个非自动存储持续时间的__autoreleasing对象,那么这个程序是不合格的。

理由:autorelease池被绑定到当前线程和范围的性质。 虽然有可能拥有实例variables被自动释放对象填充的临时对象,但是ARC没有办法在那里提供任何安全保证。

这是未定义的行为,如果一个非空指针分配给__autoreleasing对象,而autorelease池在范围内,然后该对象是在autorelease池的范围留下后读取。