声明方法参数__autoreleasing有什么好处?

an0*_*an0 7 objective-c automatic-ref-counting

根据过渡到ARC发行说明:

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

例如:

-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;

但与上述相比,上述优点有哪些:

-(BOOL)performOperationWithError:(NSError * __strong *)error;


更新:

几个答案是指临时VAR招编译器处理为var和参数之间的不匹配的优势__autoreleasing.我不明白为什么编译器不能为__strong参数做同样的技巧.我的意思是,对于__weakvar和__strong参数,编译器可以类似地执行此操作:

NSError * __weak error;
NSError * __strong tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
if (!OK) {
    // Report the error.
}
Run Code Online (Sandbox Code Playgroud)

编译器知道-(BOOL)performOperationWithError:(NSError * __strong *)error;返回一个强引用(+1),所以它像任何new-family方法一样处理它.由于tmp生活在相同的范围内error,编译器可以合理地保持它活着,只要error这样__weak引用(error)现在由__strongreference(tmp)支持,并且在范围结束之前不会无效.

Gab*_*lla 8

TL;博士

在这种情况下隐式地将__weak对象转换为对象__strong会改变程序的语义,这是编译器永远不应该做的事情.


场景

我们来举个例子吧

NSError *error;
BOOL success = [myObject performOperationWithError:&error];
if (!success) {
    // Report the error
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下error,ARC将自动推断出局部变量__strong.

同时error论证

-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
Run Code Online (Sandbox Code Playgroud)

是类型的NSError * __autoreleasing *.

请注意,在任何情况下,ARC都会将reference(id *)传递的参数推断为类型id __autoreleasing *,因此上述签名相当于

-(BOOL)performOperationWithError:(NSError **)error;
Run Code Online (Sandbox Code Playgroud)

在ARC下.

因此我们有一个不匹配,因为我们将一个带__strong注释的变量传递给一个期望__autoreleasing参数的方法.

在引擎盖下

在我们的示例中,编译器将通过创建局部__autoreleasing tmp变量来解决这种不匹配问题 .

代码变成了

NSError * __strong error;
NSError * __autoreleasing tmp = error;
BOOL success = [myObject performOperationWithError:&tmp];
error = tmp;
if (!success) {
    // Report the error.
}
Run Code Online (Sandbox Code Playgroud)

替代

我们现在假装我们可以改变签名performOperationWithError:.

如果我们想避免使用tmp变量的"编译器技巧" ,我们可以将我们的签名声明为

-(BOOL)performOperationWithError:(NSError * __strong *)error;
Run Code Online (Sandbox Code Playgroud)

我们有一个__strong变量,我们现在将它传递给一个期望__strong参数的方法,所以我们只是消除了不匹配.

看起来不错,为什么不总是声明__strong参数?

一个原因是声明参数__autoreleasing将使方法甚至接受__weak引用.

在当前的例子中它没有多大意义,但是可能存在这样的情况:我们希望__weak通过引用传递变量并声明__autoreleasing(或让ARC推断它)将允许我们这样做.

ARC将应用上面看到的相同技巧,创建一个__autoreleasing tmp变量.

结论

到目前为止提出的机制是以pass-by-writeback的名义进行的.

这种机制的设计一起工作__autoreleasing,__strong__weak变量,从而使程序员可以安全地依赖于编译器中的类型推断,而不是太在意周围的注释变量.

id __strong *在某些情况下声明参数可能有意义,但通常它可能会导致编译器生成意外错误.

我的建议是:"让编译器发挥他的魔力,你会很好"

更新

我不明白为什么编译器不能为__strong参数做同样的技巧.

告诉编译器以一种__autoreleasing方式处理一个__strong或一个__weak变量的管理,因为它基本上意味着:"请,编译器,自动做正确的事情".

这就是为什么上面看到的技巧可以毫无问题地运作.

另一方面,如果你声明一个变量,因为__weak你可能有充分的理由这样做,而你想要的最后一件事就是在你明确指出的时候隐含地保留它.这将从根本上改变你编写的代码片段的语义,因此编译器不会这样做(感谢上帝!).

换一种说法

__weak - > __autoreleasing
__strong - > __autoreleasing
__weak < - > __strong 错了!