问题
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