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

Pro*_*ber 114 memory-management objective-c ios automatic-ref-counting

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

__strong是所有Objective-C可保留对象指针的默认值,如NSObject,NSString等.这是一个强大的参考.ARC -release在范围的末尾与a平衡.

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

__weak就像__unsafe_unretained不同之处在于它是一个自动归零弱引用这意味着该指针将零一旦引用的对象被释放被设置为.这消除了悬空指针和EXC_BAD_ACCESS错误的危险.

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

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

要么

NSError *error = nil;
[database save:&error];
Run Code Online (Sandbox Code Playgroud)

在ARC下必须以这种方式声明:

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

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

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

Mac*_*ade 67

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

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

所有这些都在ARC过渡指南中得到了很好的解释.

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

NSError * e = nil;
Run Code Online (Sandbox Code Playgroud)

将转变为:

NSError * __strong error = nil;
Run Code Online (Sandbox Code Playgroud)

当你打电话给你的save方法:

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

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

NSError * error = nil;
[ database save: &error ];
Run Code Online (Sandbox Code Playgroud)

将转变为:

NSError * __strong error = nil;
NSError * __autoreleasing tmpError = error;
[ database save: &tmpError ];
error = tmpError;
Run Code Online (Sandbox Code Playgroud)

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

  • 为什么__autoreleasing限定符放在星星之间,而不仅仅是在NSError**之前?这看起来很奇怪,因为类型是NSError**.或者是因为这是试图表明指向的NSError*指针必须被限定为指向自动释放的对象? (7认同)
  • 不,`__autoreleasing`仅用于通过引用传递的参数.这是一种特殊情况,因为你有一个指向对象指针的指针.对于像构造函数这样的东西,情况并非如此,因为它们只返回指向对象的指针,并且当ARC自动处理它时. (3认同)
  • 那么为什么Apple接口似乎都没有呢?例如,NSFileManager.h中的所有内容? (2认同)

Bin*_*man 34

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

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

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

NSError * __qualifier someError;
Run Code Online (Sandbox Code Playgroud)

编译器会原谅这个:

__qualifier NSError *someError;
Run Code Online (Sandbox Code Playgroud)

但这不正确.请参阅Apple ARC过渡指南(请阅读"您应该正确装饰变量......"一节).

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

SomeClass * __qualifier *someVariable;
Run Code Online (Sandbox Code Playgroud)

因此,在方法参数为双NSError指针的情况下,数据类型声明为:

- (BOOL)save:(NSError* __autoreleasing *)errorPointer;
Run Code Online (Sandbox Code Playgroud)

英文中的"指向__autoreleasing NSError对象指针的指针".


Gle*_*Low 15

明确的ARC规范

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

例如,代码

NSError* __autoreleasing error = someError;
Run Code Online (Sandbox Code Playgroud)

实际上转换为

NSError* error = [[someError retain] autorelease];
Run Code Online (Sandbox Code Playgroud)

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

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