6

我有一个自动合成的readonly&weak属性:

@property (nonatomic, readonly, weak) KTWindowController* windowController;

我分配合成的 ivar,然后将其添加到数组中:

_windowController = [KTWindowController controller];
[self addSubController:_windowController];

这在调试版本中运行良好。但我得到一份报告,在发布(临时)构建中,这将立即 nil _windowController,然后它尝试将 nil 添加到数组中,导致应用程序崩溃。

与 Debug 构建相比,发布(临时)构建中的哪些特定设置(优化级别?)会改变此行为?

奇怪的是,这种行为会从 Debug 版本变为 Release 版本。但是我能够重现这种行为,而且它实际上是有道理的——只是当它与调试版本中发生的事情不一致时就不行了。

建议的解决方法:

KTWindowController* windowController = [KTWindowController controller];
[self addSubController:windowController];
_windowController = windowController;

除了使用上面看到的局部变量之外,在这种情况下您会推荐什么解决方法?

4

2 回答 2

1

当您将属性声明为weak时,您承诺由其他对象负责所有权。这就是的意思。当你违反这一点时,就会发生不好的事情。因此,例如,当您编写时:

KTWindowController* windowController = [KTWindowController controller];
[self addSubController:windowController];
_windowController = windowController;

您正在履行您的义务:强临时变量windowController在此方法中处理所有权,然后再windowController subController处理所有权。

当你写

 _windowController = [KTWindowController controller];

你没有做你承诺做的事情。_windowController 很弱,所以其他人正在管理生命周期。但看!没有人管理一生!因此,我们可以随时摆脱弱变量。优化器在你的发布版本中查看这个并说,

嘿!这家伙说他不在乎这个窗口控制器是死是活,只要其他人不在乎。有些人!但这不关我的事。但是看这个:既然他不在乎,那我根本就不用做!或者,无论如何,我可以在我成功的那一刻摆脱它。

编译器只是按照您所说的去做。

您确定要将此属性设为弱属性吗?每当我在我的代码中看到这一点时,我都会检查该属性是否真的应该是弱的;通常,无论如何我都想要一个强大的财产。

于 2013-04-02T20:25:08.387 回答
0

我发现将优化级别从更改None (-O0)Fast (-O, O1)引入了这个问题。

正如这里提到的,这种行为是可以预料的。它真的应该是一个编译器警告。

我最终通过将分配移动到一行来合并解决方法中的额外行,这同样有效:

// extra local var to prevent ARC from nil'ing the weak var right away in release
KTWindowController* windowController = _windowController = 
                                                 [KTWindowController controller];
[self addSubController:windowController];
于 2013-04-02T17:30:05.470 回答