addObserverForName并删除观察者

时间:2013-08-30 20:25:05

标签: objective-c macos cocoa automatic-ref-counting objective-c-blocks

在启用了ARC的Cocoa代码中,我尝试观察Window关闭事件,如下所示。

ScanWindowController * c = [[ScanWindowController alloc] initWithWindowNibName:@"ScanWindowController"];
[scanWindowControllers addObject:c];
[c showWindow:nil];

NSMutableArray *observer = [[NSMutableArray alloc] init];
observer[0] = [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
    [scanWindowControllers removeObject:c];
    [[NSNotificationCenter defaultCenter] removeObserver:observer[0]];
}];

我认为这将在关闭后删除对控制器(c)的所有引用 窗口。 但实际上,此代码在关闭Window后不会释放ScanWindowController。 如果我使用对控制器的弱引用来编写如下,则调用ScanWindowController的dealloc。

ScanWindowController * c = [[ScanWindowController alloc] initWithWindowNibName:@"ScanWindowController"];
[scanWindowControllers addObject:c];
[c showWindow:nil];

__weak ScanWindowController * weak_c = c;
NSMutableArray *observer = [[NSMutableArray alloc] init];
observer[0] = [[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
    [scanWindowControllers removeObject:weak_c];
    [[NSNotificationCenter defaultCenter] removeObserver:observer[0]];
}]; 

为什么第一个代码不起作用?

1 个答案:

答案 0 :(得分:3)

我认为保留周期介于observer数组和块之间。 observer数组包含实际的观察者对象。只要观察者对象存活,它就会占据块。该块保存observer数组。

这使ScanViewController成为副作用。我没有看到ScanViewController强烈提及观察者的证据。

我相信解决方案是从块末尾的observer数组中删除观察者。另一个解决方案是不使用数组来保存观察者,只是一个__block id变量。然后,在块的末尾将该变量设置为nil