0

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

但是,我对 ARC 的理解让我认为这只是一个侥幸/怪癖,而 ARCnil didSaveObserver之前可能会removeObserver:。看到 asdidSaveObserver永远不会保留(唯一的分配是对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) Instruments 报告存在保留周期。

4

2 回答 2

0

首先,您为什么认为它会创建一个保留循环?该块将保留didSaveObserver,是的。会didSaveObserver保留块吗?除了可用于removeObserver:删除添加的观察之外,没有任何关于返回的观察者对象的记录。它可能以某种方式保留了块或者是块本身,在这种情况下,它会创建一个保留循环。如果你想安全,是的,你可以weak用来指代块中的观察者。

看到 didSaveObserver 永远不会保留(唯一的分配是弱变量),那么 ARC 可以/(应该?)立即释放它。

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

于 2013-04-22T23:29:40.963 回答
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.

当然,这仅解释了这种特定情况。

于 2013-04-22T13:21:52.870 回答