2012-04-26 44 views
17

綜觀各種蘋果的例子去除觀察員NSNotificationCenter(例如Add Music)中,我看到他們在viewDidLoad添加觀察員默認NSNotificationCenter,然後在dealloc刪除它們。這看起來很危險,因爲viewDidLoad可以多次調用,而不需要調用dealloc。然後這將多次添加相同的觀察者,導致處理程序被多次調用。中添加和一個UIViewController

對此的解決方案也將刪除viewDidUnload中的觀察者,但這意味着同一觀察者可能會在dealloc中第二次被刪除,這似乎是一個潛在的問題。

我錯過了什麼?

+3

我不認爲刪除不存在的觀察者有任何不利影響。 – jbat100 2012-04-26 12:38:59

+0

@ jbat100謝謝。我絕對會想在dealloc和viewDidUnload中移除觀察者,這是唯一的出路。 – Undistraction 2012-04-26 14:33:30

回答

24

關於以正確的方式刪除通知有很多討論。例如:

我建議你刪除viewWillDisappear(或viewDidDisappear)和viewDidUnload生命週期方法觀察員。 (注:viewDidUnload已被廢棄,不應該在iOS6的+實施;見iOS 6 - viewDidUnload migrate to didReceiveMemoryWarning?

的重要說明:

viewDidUnload不能保證被調用 - 它不是一個標準的生命週期方法。

從蘋果DOC:

viewDidUnload 當低內存條件發生並且不需要當前視圖控制器的 視圖,該系統可以選擇從 內存中刪除這些看法。這個方法在視圖控制器的視圖 被釋放後調用,並且是您執行任何最終清理的機會。

而是,只要該接收器的引用數量爲零,就調用dealloc

希望它有幫助。

編輯

爲了完整起見,你可以看到如何avoid-nsnotification-removeobserver此鏈接。該鏈接爲刪除觀察者提供了一些有用的指導(另見評論)。作者在viewDidAppear/viewDidDisappear方法中執行該操作,因爲viewWillAppearviewWillDisappear在許多應用程序中並不總是被正確調用。 這是您的選擇。

如果您想確保以正確的方式刪除觀察者,請在dealloc方法中取消註冊,或者當您在第二條評論中寫入完全卸載視圖時。 但請確保將來會撥打dealloc。換句話說,正如我已經提到的,如果控制器繼續保持活動狀態,因爲其他對象有一個引用它,該方法將永遠不會被調用。在這種情況下,控制器將繼續收到通知。

+0

謝謝。但正如你所說; 'viewDidUnload在dealloc方法之前未被調用。有時一個VC的dealloc將被調用,而viewDidUnload被調用,在這種情況下,使用你的建議意味着VC在解除分配後留作觀察者,因爲viewWillDisappear/viewDidunload永遠不會被調用。或者viewWillDisappear絕對保證在dealloc之前調用? – Undistraction 2012-04-26 14:30:51

+1

@ 1ndivisible * viewWillDisappear *在視圖從屏幕消失之前調用。這意味着當你從屏幕上移除視圖的控制器時(例如控制器從導航控制器彈出),該方法被調用。我爲你添加了一個編輯。 – 2012-04-26 15:02:26

+1

不錯。 avoid-nsnotification-removeobserver鏈接是一個不錯的選擇。不知道。 – Undistraction 2012-04-26 15:55:46

2

爲什麼你不會在viewWillAppear/viewDidDisappear?無論如何你只是在關注通知的時候,對嗎?

+0

但據我所知,如果對象被釋放,則不保證會調用viewDidDisappear。如果不是,則在釋放對象後,該對象將留作觀察者。 – Undistraction 2012-04-26 14:32:30

+0

顯然他們將永遠被稱爲。 (見上) – Undistraction 2012-04-26 16:23:30

+1

沒有在某些應用程序人們關心什麼時候視圖沒有顯示,即更新數據狀態 – jini 2012-12-22 20:32:57

2
- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 
    [[NSNotificationCenter defaultCenter] addObserver:self .........] 
} 

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 
    [[NSNotificationCenter defaultCenter] removeObserver:self .........]; 
} 
0

您可以在viewWillAppear中添加Observer,並在viewWillDisappear中移除Observer。 但viewWillAppear可能會調用很多次。所以你可以先移除通知然後再移除addObserver。

-(void)viewWillAppear:(BOOL)animated{ 
    [super viewWillAppear:YES]; 
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil]; 
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(keyboardWillShow:)name:@"UIKeyboardWillShowNotification"object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(keyboardWillHide:)name:@"UIKeyboardWillHideNotification"object:nil]; 
} 

-(void)viewWillDisappear:(BOOL)animated{ 
[super viewWillDisappear:YES]; 
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil]; 
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil]; 
} 
1

對於在這個頁面上磕磕絆絆的人,最近可能不再需要刪除觀察者。該"Discussion" section of the addObserver(_:selector:name:object:) docs說:

如果您的應用程序的目標的iOS 9.0及更高版本或MacOS的10.11及更高版本,你不需要在它dealloc方法來註銷一個觀察者。否則,您應該在observer之前調用removeObserver(_:name:object:),否則任何傳遞給此方法的對象都將被釋放。

相關問題