有人可以向我解释在以下示例代码块中使用__autoreleasing
的目的吗?
- (void)execute:(NSError * __autoreleasing *)error {
// do stuff, possibly assigning error if something went wrong
}
我删除了__autoreleasing
,一切似乎仍然可以编译/运行。我开始使用obj-c后ARC,所以我从来没有真正学过/理解所有那些双下划线的东西。我已阅读ARC transition guide,但我并不完全了解他们的NSError示例。
答案 0 :(得分:72)
考虑ARC如何使用变量 - 每个参考变量都有一个模式(隐式或显式):强,弱等。模式让我们的ARC知道如何处理对该变量的读写操作;例如对于强变量读取,在写入时需要释放变量中的现有引用,然后才能将其替换为新变量。 ARC需要知道任何变量的模式才能运行。
现在考虑本身由引用传递的变量,例如对于您的execute
,您可以按以下方式拨打电话:
NSError *myError = nil;
...
[someObject execute:&myError]; // pass the variable itself by reference, not the variables value
并且execute
的正文将包含以下行的分配:
- (void)execute:(NSError * __autoreleasing *)error
{
...
if (error != NULL)
*error = [NSError ...]; // assign indirectly via the reference to a variable
...
}
现在,对于间接分配,ARC需要知道引用变量的模式,因此它知道如何读写。这就是__autoreleasing
在声明中的含义,它告诉ARC它已经传递了对模式为 autoreleasing 的变量的引用,并告诉ARC如何读取和写入内容变量。删除__autoreleasing
并假定默认模式,在这种情况下我建议明确肯定是好的。
autoreleasing 模式意味着变量包含一个不拥有的引用,如果需要,读取应该保留,写入可以写入。它主要用于通过引用传递的变量。
您可能会注意到,在上面的示例中,变量myError
具有模式 strong (隐式),但它通过引用传递为 autoreleasing - 编译器通过引入临时自动释放变量自动处理此问题,复制而不将myError
中的当前引用保留到其中,并将临时引用作为参数传递给execute:
。在调用返回后,编译器执行从临时到myError
的正常分配,这会导致释放任何旧引用并保留返回的引用。
有关详细信息,请参阅Apple's Transitioning to ARC Release Notes
跟进评论
问:__autoreleasing
是否隐式设置?
答:好的Apple's文档并不具体,但Clang documentation表示它对于间接参数是隐含的。如上所述,我建议明确,清晰度是一件好事。
问:这个位置是否重要?
答:是的,没有......这是一个C声明,是测验问题的内容(“以下是什么声明......”)。限定符应该在两个星号之间,因为它是一个指向(对象的变量)自动释放指向对象的指针的指针,但Apple声明编译器是“宽容”而不具体说明它原谅的内容。安全地玩,把它放在正确的地方。问:在进行间接分配之前,您是否应该测试error
为NULL
?
答:当然你应该在你做间接之前的某个地方。显示的代码只是一个大纲,...
的详细信息已被删除和覆盖。然而,由于多年来已经提高了几次,我可能已经过多了,已经添加了一个合适的if
。