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

In which situations do we need to write the __autoreleasing ownership qualifier under ARC?

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

__strong是所有Objective-C可保留对象指针(如nsObject、nsString等)的默认值。这是一个有力的参考。ARC在作用域的末尾将其与一个-release进行平衡。

__unsafe_unretained等于老办法。它用于弱指针而不保留可保留对象。

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

但是,究竟__autoreleasing有什么好处呢?当我需要使用这个限定符时,我很难找到实际的例子。我相信它只适用于需要指针指针的函数和方法,例如:

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

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

必须按照以下方式声明:

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

但这太含糊了,我想完全理解为什么。我找到的代码片段把"自动租赁"放在两颗星之间,这对我来说很奇怪。类型是NSError**(指向nserrror的指针),那么为什么把__autoreleasing放在恒星之间,而不是仅仅放在NSError**前面?

另外,在其他情况下,我必须依赖于__autoreleasing


你说得对。如官方文件所述:

__autoreleasing to denote arguments that are passed by reference (id *) and are autoreleased on return.

所有这些在弧过渡指南中都有很好的解释。

在您的nserrror示例中,声明意味着__strong,隐含地:

1
NSError * e = nil;

将转换为:

1
NSError * __strong error = nil;

调用save方法时:

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

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

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

将转换为:

1
2
3
4
NSError * __strong error = nil;
NSError * __autoreleasing tmpError = error;
[ database save: &tmpError ];
error = tmpError;

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


跟进Macmade的回答和自豪会员在评论中的后续问题(也会将此作为评论发布,但超过了最大字符数):

这就是为什么uu autoreleasing的变量限定符放在两颗星之间的原因。

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

1
NSError * __qualifier someError;

编译器会原谅这一点:

1
__qualifier NSError *someError;

但这是不正确的。请参阅《Apple Arc Transition Guide》(Apple Arc Transition指南)(请阅读以"您应该正确地修饰变量…"开头的部分)。

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

1
SomeClass * __qualifier *someVariable;

因此,对于双nserrror指针的方法参数,数据类型声明为:

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

它的英文意思是"指向自动释放nserrror对象指针的指针"。


最终的ARC规范指出

For __autoreleasing objects, the new pointer is retained, autoreleased, and stored into the lvalue using primitive semantics.

例如,代码

1
NSError* __autoreleasing error = someError;

实际转换为

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

…这就是为什么当你有一个参数NSError* __autoreleasing * errorPointer时,被调用的方法会把错误分配给*errorPointer,上面的语义就会开始。

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