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

我在努力完成拼图。

__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];

根据《反腐败公约》 ,必须以下列方式宣布:

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

But this is too vague and I'd like to fully understand 为什么. The code snippets I find place the __autoreleasing inbetween the two stars, which looks weird to me. The type is NSError** (a pointer-pointer to NSError), so why place __autoreleasing inbetween the stars and not simply in front of NSError**?

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

29244 次浏览

你说得对,正如官方文件解释的那样:

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

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

In your NSError example, the declaration means __strong, implicitly:

NSError * e = nil;

将改为:

NSError * __strong error = nil;

调用 save方法时:

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

The compiler will then have to create a temporary variable, set at __autoreleasing. So:

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

Will be transformed to:

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

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

definitive ARC specification显示

对于 _ _ autorelease 对象,使用基本语义将新指针保留、自动释放并存储到左值中。

例如,代码

NSError* __autoreleasing error = someError;

实际上被转化为

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

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

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

跟进 Macmade 的回答和骄傲会员在评论中的跟进问题(也可以作为评论发布,但它超过了最大字符数) :

下面是 _ _ autorelease 的变量限定符被放置在两颗星之间的原因。

首先,用限定符声明对象指针的正确语法是:

NSError * __qualifier someError;

编译器会原谅这一点:

__qualifier NSError *someError;

但它是不正确的。参见 苹果 ARC 过渡指南(请阅读“您应该正确地装饰变量...”)。

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

SomeClass * __qualifier *someVariable;

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

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

which in English says "pointer to an __autoreleasing NSError object pointer".

简而言之: 这只是为了与 MRC 兼容。

Apple have made agreement that in own libraries objects returned by ** are always autoreleased. So ARC code will work fine with old binaries (for example if you have deployment target iOS 4) and vise versa MRC code will work fine with ARC binaries.

所以总结一下:

  • 永远不要使用 __autoreleasing: 编译器会在需要的地方自动添加它

  • 如果您不打算支持 MRC 代码,那么您应该在任何地方都使用 * __strong *。它将避免家庭破裂:

    @autoreleasingpool {
    *autorelesingOut = [@"crash maker" mutableCopy];//NSString * __autoreleasing *autorelesingOut;
    *strongOut = [@"it's ok" mutableCopy];//NSString * __strong *strongOut;
    //App will crash if autorelesingOut will be referenced outside of this autoreleasepool
    }