如何正确处理“在ARC模式下,弱引用可能会不可预测地为空”的问题

18

我在Xcode中打开了一个新的标志,并得到了警告:“在ARC模式下,弱接收器可能是不可预测的空值”。这让我感到困惑,因为当然它可能是nil。

1个回答

27

我一周前提出了这个问题,没有得到答案,但Greg Parker在邮件列表上回答了我的问题。因此,我要重新发布这个问题,并附上答案。

我们添加了这个警告,是因为我们在实践中看到了很多微妙且难以调试的问题。

推荐的做法是将弱变量读入一个强局部变量中一次,然后使用该局部变量。

  • Greg Parker

在我第一次发布这个问题时,我发了类似下面的东西,当时我认为测试nil就足够了。

if (self.rootViewController) {
    [self.rootViewController controllerWillChangeContent:controller];
}
问题在于,在检查为nil和完成调用方法之间,self.rootViewController可能会变成nil。我们被告知要做的是赋值给一个强大的本地引用并像这样使用它。
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    RootViewController *rootVC = self.rootViewController;
    if (rootVC) {
        [rootVC controllerWillChangeContent:controller];
    }
}

Stephen Butler 简明扼要地重述了这个警告的目的是为了解决什么问题。

我们试图防止对象实例在你调用它(通过一个弱引用)并且没有任何强引用持有该对象的情况下,在 [someMethod] 中被释放。


2
看起来,只需将弱引用分配给强引用就足以消除警告。在上面的第二个示例中,对nil进行的检查是不必要的,因为对nil发送消息会被简单地忽略掉。唯一有用的时候是在目标为nil时可以跳过很多工作,如果结果将被忽略或丢失。 - big_m
2
此外,根据上述引用帖子的后续,警告的真正重点似乎不在于捕获发送给nil的消息,而在于防止对象在正在服务消息时被释放。在调用方法的生命周期内保持强引用可以防止这种情况发生。 - big_m
@griotspeak,如果我可以再补充一点,我认为在你的回答中也引用一下我上面链接的Stephen Butler的帖子会更清晰;Greg Parker的引用告诉你如何避免警告,但是Stephen的解释了为什么要这样做,这是我想看到的。尽管你提到了它,但我发现信息在示例之间丢失了,直到我阅读了你引用的整个线程(巧合的是,当我谷歌警告信息时,这篇帖子就是第二个搜索结果)。 - big_m
1
Stephan Butler是错误的,如果您直接在弱变量上调用方法,clang将首先保留它,然后调用该方法,最后再次释放它。当向弱变量发送消息时,在调用返回之前,对象__不能__被解除分配!但是,如果您向弱变量发送消息,则每次调用都会保留/释放它,这是巨大的性能惩罚。请参见https://dev59.com/g2Up5IYBdhLWcg3wz54H#15033758 - Mecki
那么,如果最终我们必须创建一个强引用来防止警告,为什么要在我们的属性中使用“weak”呢? - Anel Rojas Hernández
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接