在ARC中使用NSNotificationCenter代码块方法时,不会调用控制器dealloc

时间:2012-10-02 22:09:42

标签: iphone ios uiviewcontroller nsnotificationcenter dealloc

当我在视图控制器的-addObserverForName: object: queue: usingBlock:方法中使用NSNotificationCenter -viewDidLoad:时,-dealloc方法最终未被调用。

(当我删除-addObserverForName: object: queue: usingBlock:时,再次调用-dealloc。)

使用-addObserver: selector: name: object:似乎没有这个问题。我究竟做错了什么? (我的项目是使用ARC。)

以下是我的实施示例,以防我在这里做错了什么:

[[NSNotificationCenter defaultCenter] addObserverForName:@"Update result"
                                                  object:nil
                                                   queue:nil
                                              usingBlock:^(NSNotification *note) {
                                                  updateResult = YES;
                                              }];

提前感谢您的帮助。

我尝试添加以下内容(无济于事):

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    if ([self isMovingFromParentViewController]) {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
}

3 个答案:

答案 0 :(得分:17)

updateResult是一个实例变量,它可以防止对象被该块保留而取消分配。

换句话说,你有一个保留周期。对象保留块,块保留对象。

您需要创建一个弱或不安全的对该实例的引用及其变量,以便失去该关系。

在通知栏之前添加以下内容:

__unsafe_unretained YouObjectClass *weakSelf = self;

或(如果您使用的是iOS5及以上版本)

__weak YouObjectClass *weakSelf = self;

然后,在该块中,通过新的弱引用引用该对象:

[[NSNotificationCenter defaultCenter] addObserverForName:@"Update result"
                                                  object:nil
                                                   queue:nil
                                              usingBlock:^(NSNotification *note) {
                                                  weakSelf.updateResult = YES;
                                              }];

请注意,保留周期本身并不是一件坏事。有时你真的希望它们发生。但是那些是你确定循环将在特定时间后被破坏的情况(例如动画块)。一旦块执行并且从堆栈中移除,循环就会中断。

答案 1 :(得分:6)

这很可能是因为你有一个保留周期。

当您的块隐式保留self时,通常就是这种情况,并且self会以某种方式保留块。你将有一个保留周期,因为每个人保留另一个保留周期,因此他们的retainCount永远不会达到零。

您应该激活警告-Warc-retain-cycles,警告您这些问题。

因此,在您的情况下,您使用变量updateResult,我假设它是一个实例变量,并且隐式保留self。您应该使用临时弱变量来表示self,并在块中使用它,这样它就不会被保留并且会中断保留周期。

__block __weak typeof(self) weakSelf = self; // weak reference to self, unretained by the block
[[NSNotificationCenter defaultCenter] addObserverForName:@"Update result"
                                              object:nil
                                               queue:nil
                                          usingBlock:^(NSNotification *note) {
                                              // Use weakSelf explicitly to avoid the implicit usage of self and thus the retain cycle
                                              weakSelf->updateResult = YES;
                                          }];

答案 2 :(得分:0)

这不是保留周期。

NSNotificationCenter按住该区块,区块为self。因为[NSNotificationCenter defaultCenter]是一个生活在所有应用生命周期中的单身人士,所以它保持self间接。