防止弱分配变量在不创建保留周期的情况下被解除分配

时间:2013-04-22 10:42:34

标签: cocoa-touch cocoa automatic-ref-counting objective-c-blocks nsnotificationcenter

我有一个奇怪的案例涉及ARC,NSNotificationCenter和一个块。以下是代码的简化示例。从测试来看,似乎didSaveObserver的内存管理正在按预期执行,即它没有创建保留周期,并且在nil之前没有removeObserver:

然而,我对ARC的理解让我觉得这只是一个侥幸/怪癖,而ARC可以在nil之前didSaveObserver removeObserver:。从未保留didSaveObserver(唯一的分配是weak变量),然后ARC可以/(应该)立即解除它。

我是否正确理解了ARC规则?如果是,那么我如何确保didSaveObserver被保留以便可以不被观察但不创建保留周期?

self.willSaveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextWillSaveNotification object:nil queue:nil usingBlock:^(NSNotification *note) {

    id preSaveState = ...; //Store some interesting state about a Core Data object (the details aren't significant to this question).

    __weak __block id didSaveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
    //Unobserve the did save block. This is the tricky bit! didSaveObserver must be __weak to avoid a retain cycle, but doing so also means that the block may be dealloced before it can be unobsered.
    [[NSNotificationCenter defaultCenter] removeObserver:didSaveObserver];        

        id postSaveState = ...;
        //Perform work that uses pre & post save states.
    }];
}];

更多详情:

如果未添加__weak(默认为__strong),仪器会报告保留周期。

2 个答案:

答案 0 :(得分:0)

NSNotification.h中有一条评论解释了为什么didSaveObserver在这种特殊情况下没有被解除分配:

// The return value is retained by the system, and should be held onto by the caller in
// order to remove the observer with removeObserver: later, to stop observation.

当然,这只能解释这个具体案例。

答案 1 :(得分:0)

首先,您认为为什么会创建保留周期?该块将保留didSaveObserver,是的。 didSaveObserver会保留该区块吗?除了可以在removeObserver:中使用以删除添加的观察值之外,没有任何关于返回的观察者对象的文档。它可能以某种方式保留块或块本身,在这种情况下它将创建保留周期。如果您想要安全,是的,您可以使用weak来引用块中的观察者。

  

从未保留过看到didSaveObserver(唯一的任务是   一个弱变量),然后ARC可以/(应该)立即解除它。

除非通知中心在返回给您之前保留它。