问题
On Cocoa code with ARC enabled, I tried to observe Window closing events like below.
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]];
}];
I thought this will remove all the references to the controller (c) after closing Window. But actually, this code does not dealloc ScanWindowController after closing Window. If I wrote like below using weak reference to the controller, dealloc of ScanWindowController is called.
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]];
}];
Why does the first code not work?
回答1:
I think the retain cycle is between the observer array and the block. The observer array holds the actual observer object. So long as the observer object is alive, it holds the block. The block holds the observer array.
This keeps the ScanViewController as a side effect. I see no evidence that the ScanViewController holds a strong reference to the observer.
I believe the solution is to remove the observer from the observer array at the end of the block. Another solution would be to not use an array to hold the observer, just a __block id variable. Then, set that variable to nil at the end of the block.
来源:https://stackoverflow.com/questions/18540946/addobserverforname-and-removing-observer