防止ARC在分配后立即使用弱的ivar(在发布版本中)

时间:2013-04-02 16:51:44

标签: objective-c automatic-ref-counting weak-references

我有一个自动合成的readonly& weak财产:

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

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

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

这在Debug版本中工作正常。但我得到一个报告,在发布(ad hoc)版本中,这将立即使_windowController无效,然后它会尝试将nil添加到数组中,从而导致应用程序崩溃。

与Debug版本相比,发布(ad hoc)版本中的哪些特定设置(优化级别?)会改变此行为?

令我感到奇怪的是,这种行为会从Debug版本变为Release版本。但我能够重现这种行为,它实际上是有意义的 - 只是当它与调试版本中发生的事情不一致时。

建议的解决方法:

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

除了如上所示使用本地变量之外,在这种情况下,您会推荐哪种解决方法?

2 个答案:

答案 0 :(得分:1)

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

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

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

当你写

 _windowController = [KTWindowController controller];
你没有做你应许做的事。 _windowController很弱,所以其他人正在管理生命周期。但看!没有人管理一生!所以我们可以随时摆脱弱变量。优化器会在您的发布版本中查看此内容并说,

  

喂!这家伙说他不关心这个窗户控制器是否存在或生死,只要没有其他人关心。有些人!但这不关我的事。但是看看这个:因为他不在乎,我根本不需要做到这一点!或者,无论如何,我可以立即摆脱它。

编译器正在做你想说的事情。

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

答案 1 :(得分:0)

我发现将优化级别从None (-O0)更改为Fast (-O, O1)会引发此问题。

As mentioned here,这种行为是可以预期的。它确实应该是编译器警告。

我最终通过将分配移动到一行来合并解决方法中的额外行,这也适用:

// extra local var to prevent ARC from nil'ing the weak var right away in release
KTWindowController* windowController = _windowController = 
                                                 [KTWindowController controller];
[self addSubController:windowController];