ChatGPT解决这个技术问题 Extra ChatGPT

在什么情况下,我们需要在 ARC 下编写 __autoreleasing 所有权限定符?

我正在尝试完成这个谜题。

__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

我有同样的问题,下面的答案并不完全令人信服......例如,为什么系统不提供接口来接受像你这样的 __autoreleasing 装饰器声明的 NSError** 参数,以及 Transitioning to Arc 发行说明说他们应该?例如,NSFileManager.h 中的许多这些例程中的任何一个?

I
Imre Kelényi

你是对的。正如官方文档解释的那样:

__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 来避免这种情况。


不,__autoreleasing 仅用于通过引用传递的参数。这是一种特殊情况,因为您有一个指向对象指针的指针。便利构造函数之类的东西并非如此,因为它们只返回一个指向对象的指针,并且 ARC 会自动处理它。
为什么 __autoreleasing 限定符放在星星之间,而不是放在 NSError** 前面?这对我来说看起来很奇怪,因为类型是 NSError**。还是因为这试图表明指向的 NSError* 指针必须被限定为指向自动释放的对象?
@Proud Member 关于您的第一条评论 - 这是不正确的(如果我理解正确的话) - 请参阅下面的 Glen Low 的回答。错误对象被创建并分配给保存函数内的自动释放变量(您传入的变量)。此分配导致对象在当时被保留和自动释放。 save 函数的声明阻止我们向它发送除自动释放变量以外的任何东西,因为这是它所需要的——这就是为什么如果我们尝试编译器会创建一个临时变量的原因。
那么为什么苹果的界面似乎都没有这个呢?例如,NSFileManager.h 中的所有内容?
@Macmade:碰巧我注意到您的答案已被编辑(由stackoverflow.com/users/12652/comptrol),我的印象是至少对您的第一个示例的更改(“隐式......将转换为......)是错误的, 因为 __strong 限定符已从第二行移到第一行。也许你可以检查一下。
B
Binyamin Bauman

在评论中跟进 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 对象指针的指针”。


谢谢。这就是我需要的答案,您可以设置“因为指向内存地址的指针是指向原始类型的指针,而不是指向对象的指针”。粗体字,这是事情的核心。
R
Ramy Al Zuhouri

definitive ARC specification 表示

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

例如,代码

NSError* __autoreleasing error = someError;

实际上被转换为

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

...这就是为什么当您有参数 NSError* __autoreleasing * errorPointer 时它起作用的原因,然后被调用的方法会将错误分配给 *errorPointer 并且上述语义将起作用。

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


C
Cy-4AH

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

Apple 已同意在自己的库中 ** 返回的对象始终是自动释放的。因此,ARC 代码适用于旧的二进制文件(例如,如果您的部署目标是 iOS 4),反之亦然,MRC 代码适用于 ARC 二进制文件。

所以总而言之:

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

如果你不打算支持 MRC 代码,那么你应该在任何地方使用 * __strong *。它将从家庭崩溃中保存:@autoreleasingpool { *autorelesingOut = [@"crash maker" mutableCopy];//NSString * __autoreleasing *autorelesingOut; *strongOut = [@"没关系" mutableCopy];//NSString * __strong *strongOut; //如果 autorelesingOut 将在此 autoreleasepool 之外被引用,应用程序将崩溃 }


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅