1

在啓用ARC的Cocoa代碼上,我嘗試觀察如下的窗口關閉事件。addObserverForName和刪除觀察者

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]]; 
}]; 

爲什麼第一個代碼不起作用?

回答

3

我認爲保留週期介於observer陣列和塊之間。 observer數組包含實際的觀察者對象。只要觀察者對象處於活動狀態,它就包含該塊。該塊保存着observer陣列。

這可以保持ScanViewController的副作用。我沒有看到證據顯示ScanViewController對觀察者有強烈的參考。

我相信解決的辦法是從模塊末尾的observer數組中刪除觀察者。另一個解決方案是不使用數組來保存觀察者,只是一個__block id變量。然後,在該塊的末尾將該變量設置爲nil

+0

** observer **是局部變量,ARC已啓用。所以,在函數結束時,** observer **數組和內容應該被釋放? –

+1

ARC確實**不保證當局部變量超出範圍時,由局部變量引用的對象被銷燬。 *一個引用將被釋放,但這並不意味着該對象被釋放。該塊包含對它的另一個引用,只要觀察對象(由'-addObserverForName:object:queue:usingBlock:'返回的那個)存在,該塊就會保留。只要存在'observer'數組,這個觀察對象就存在,這就是保留週期。 –

+0

啊,我明白了!所以,我寫了** arr = @ []; arr [0] = arr; **。只要在塊末尾調用** [observer removeAllObjects] **解決了參考循環。謝謝 ! –