在哪些情况下我们需要在ARC下编写__autoreleasing所有权限定符?

时间:2012-01-14 11:52:25

标签: objective-c ios memory-management automatic-ref-counting

我正在努力完成这个难题。

__strong是所有Objective-C可保留对象指针的默认值,如NSObject,NSString等。它是一个强大的引用。 ARC在范围的末尾与-release进行平衡。

__unsafe_unretained等于旧的方式。它用于弱指针而不保留可保留对象。

__weak__unsafe_unretained类似,只是它是一个自动归零的弱引用,意味着一旦引用的对象被释放,指针就会被设置为nil。这消除了悬空指针和EXC_BAD_ACCESS错误的危险。

__autoreleasing到底有什么用呢?我很难找到关于何时需要使用此限定符的实际示例。我相信它只适用于期望指针指针的函数和方法,例如:

- (BOOL)save:(NSError**);

NSError *error = nil;
[database save:&error];
在ARC下的

必须以这种方式声明:

- (BOOL)save:(NSError* __autoreleasing *);

但这太模糊了,我想完全理解为什么。我找到的代码片段将__autoreleasing放在两颗星之间,这对我来说很奇怪。类型是NSError**(指向NSError的指针指针),那么为什么要将__autoreleasing放在星星之间而不是简单地放在NSError**之前?

此外,可能还有其他情况我必须依赖__autoreleasing

3 个答案:

答案 0 :(得分:67)

你是对的。正如官方文件所述:

  

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

所有这些都在ARC transition guide中得到了很好的解释。

在NSError示例中,声明意味着__strong,隐含地:

NSError * e = nil;

将转变为:

NSError * __strong error = nil;

当您拨打save方法时:

- ( BOOL )save: ( NSError * __autoreleasing * );

然后编译器必须创建一个临时变量,设置为__autoreleasing。所以:

NSError * error = nil;
[ database save: &error ];

将转变为:

NSError * __strong error = nil;
NSError * __autoreleasing tmpError = error;
[ database save: &tmpError ];
error = tmpError;

您可以通过直接将错误对象声明为__autoreleasing来避免这种情况。

答案 1 :(得分:33)

在评论中跟进Macmade的答案和Proud Member的后续问题,(也会将其作为评论发布,但它超出了最大字符数):

这就是__autoreleasing的变量限定符放在两颗星之间的原因。

前言,使用限定符声明对象指针的正确语法是:

NSError * __qualifier someError;

编译器会原谅这个:

__qualifier NSError *someError;

但这不正确。请参阅the Apple ARC transition guide(阅读开头的部分“你应该正确地装饰变量......”)。

解决手头的问题:双指针不能有ARC内存管理限定符,因为指向内存地址的指针是指向基本类型的指针,而不是指向对象的指针。但是,当您声明双指针时,ARC确实想知道第二个指针的内存管理规则是什么。这就是双指针变量指定为:

的原因
SomeClass * __qualifier *someVariable;

因此,如果方法参数是双NSError指针,则数据类型声明为:

- (BOOL)save:(NSError* __autoreleasing *)errorPointer;

英文中的“指向__autoreleasing NSError对象指针的指针”。

答案 2 :(得分:15)

definitive ARC specification

  

对于__autoreleasing对象,新指针被保留,自动释放,并使用原始语义存储到左值。

例如,代码

NSError* __autoreleasing error = someError;

实际上转换为

NSError* error = [[someError retain] autorelease];

...这就是为什么当你有一个参数NSError* __autoreleasing * errorPointer时它会起作用,然后被调用的方法会将错误分配给*errorPointer,上面的语义将会启动。

您可以在不同的上下文中使用__autoreleasing来强制ARC对象进入自动释放池,但这并不是非常有用,因为ARC似乎只在方法返回时使用自动释放池并且已经自动处理它。