考虑 ARC 如何与变量配合工作——每个引用变量都具有模式(隐式或显式):强引用,弱引用等。这种模式可以让 ARC 知道如何处理对该变量的读写操作;例如,对于强引用变量,读取不需要额外的操作,而写入需要在替换为新值之前释放变量中现有的引用。ARC 需要知道任何变量的模式才能发挥作用。
现在考虑那些通过引用本身传递的变量,例如,对于您的execute
,您将进行以下调用:
NSError *myError = nil
...
[someObject execute:&myError]
而 execute
的主体将包含类似以下的赋值语句:
- (void)execute:(NSError * __autoreleasing *)error
{
...
if (error != NULL)
*error = [NSError ...];
...
}
现在对于那个间接赋值,ARC需要知道引用变量的模式以便于读写。这就是声明中的__autoreleasing
所起的作用,它告诉ARC传递了一个引用模式为autoreleasing的变量,并且这告诉ARC如何读写变量的内容。去掉__autoreleasing
会默认假设一个模式,在这种情况下,我建议明确指定。
autoreleasing模式意味着变量包含一个未拥有的引用。如果需要,读操作应该retain,而写操作可以直接写入。主要用于通过引用传递的变量。
你可能注意到在上面的示例中,变量myError
的模式为strong(隐式),但它作为autoreleasing的引用传递 - 编译器通过引入一个临时的autoreleasing变量来自动处理这个问题,将myError
中当前引用的副本复制到其中,然后将临时变量作为execute:
的参数按引用传递。调用返回后,编译器从临时变量进行正常的赋值到myError
,这会释放任何旧引用并保留返回的引用。
有关更多详细信息,请参见苹果公司的自动引用计数(ARC)转换发布说明
回应评论
问:是否会隐式设置__autoreleasing
?
答:嗯,苹果公司的文件没有具体说明,但是Clang文档说对于间接参数是隐含的。如上所述,我建议明确指定,清晰度是件好事™。
问:位置是否重要?
答:是和不是...这是一个C声明,经常作为问答题出现(“下面的声明是什么意思…”)。限定符应该位于两个星号之间,因为它是指向对象的autoreleasing指针类型的变量,但是苹果公司表示编译器是“宽容”的,而没有明确说明它原谅了什么。保险起见,把它放在正确的位置。
问:在进行间接赋值之前,是否应该测试error
是否为NULL
?
答:当然,应该在间接引用之前的某个地方进行测试。所示代码只是一个概述,并且这样的细节被省略了并由...
覆盖。但是由于多年来已经提出了几次,也许我省略了太多的细节,因此已添加了适当的if
。
__autoreleasing
是否会被隐式设置?另外,__autoreleasing
的放置位置是否重要(在星号之前、内部还是之后)? - chinabuffet*error
赋值之前,应该检查error
是否为NULL
。否则,由于[foo execute:NULL]
是一个完全有效的执行方式,表示“我不关心错误”,你的方法可能会导致应用程序崩溃。 - Joel*error
之前检查error
是否不是nil
或NULL
,否则可能会引发EXC_BAD_ACCESS
信号。 - pxpgraphics