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

时间:2013-01-28 01:05:02

标签: objective-c automatic-ref-counting

根据Transitioning to ARC Release Notes

  

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

例如:

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

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

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


更新

有几个答案引用temp var技巧编译器来处理var和argument之间的不匹配,作为__autoreleasing优点。我不明白为什么编译器不能为__strong参数做同样的技巧。我的意思是,对于__weak var和__strong参数,编译器可以类似地执行此操作:

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

编译器知道-(BOOL)performOperationWithError:(NSError * __strong *)error;返回一个强引用(+1),因此它就像任何new - family方法一样处理它。由于tmperror位于同一范围内,因此只要error,编译器就可以合理地使其保持活动状态,因此现在支持__weak引用(error)通过__strong引用(tmp),并且在范围结束之前不会无效。

3 个答案:

答案 0 :(得分:8)

TL;博士

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


场景

我们举一个例子

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

在这种情况下,error本地变量由ARC自动推断为__strong

同时<{p>}的error参数

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

的类型为NSError * __autoreleasing *

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

-(BOOL)performOperationWithError:(NSError **)error;
在ARC下

因此,我们将__strong带注释的变量传递给期望__autoreleasing参数的方法,因此我们存在不匹配。

引擎盖下

在我们的示例中,编译器将通过创建本地__autoreleasing tmp变量来解决此类不匹配问题。

代码变为

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

替代

我们现在假装我们可以更改performOperationWithError:的签名。

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

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

我们有一个__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 - &gt; __autoreleasing
__strong - &gt; __autoreleasing
__weak&lt; - &gt; __strong 错误!

答案 1 :(得分:2)

正如您所说,唯一的优点是该对象在返回时自动释放。所以没有ARC就像发送保留和自动释放一样。在C中,作为参数传递的每个变量都被复制,因此这不会影响对原始指针的处理,而只会影响复制的指针。

优势的一个例子可能就是这样,假设论证不是__autoreleasing:

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

所以我调用方法传递一个弱引用:

NSError* __weak error;
[object performSelectorWithError: &error];

这里发生了什么?复制的参数在返回时不会自动释放,因此当方法返回错误时为nil。如果相反,方法就是这个:

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

这种情况下,错误的保留计数仍为1,但它是自动释放的,所以它不是零,可以在池中使用。

答案 2 :(得分:1)

我没有提到的另一个原因是遵循Cocoa约定,以便ARC代码可以与非ARC代码正确地互操作。