蘋果的消息機制是個非常好用的東西,當需要在類的各個實例之間傳遞消息或者寫一些事件驅動的程序時,絕對是個不錯的工具。但是使用時一不小心就會造成引用已經被dealloc的對象的錯誤,引起程序崩潰。於是,在合適的時機addobserver和removeobserver就是個很關鍵的事情。下面,分幾種情況來闡述一下自己的一點想法。
一,使用defaultcenter。
簡單的情況下,若自己沒有太多的消息需要注冊和處理,直接使用[NSNotificationCenter defaultCenter]來調用默認的消息中心就夠用了。如果,有一些特殊的要求那么,就需要試一下一個繼承自NSnotificationcenter的子類。
二,在視圖顯示的時候接受消息。
有些時候,我們需要在一個已經顯示在主界面上的ViewController上做一點動作,比如當一個同步過程完成后,把同步的結果顯示在界面上。但是,如果這個ViewController沒有顯示在主界面上的話,它就不關心同步結果是什么樣子了。所以這個時候,我們可以在viewwillappear或者viewdidapper中addobserver添加消息監聽。然后在viewwilldisappear和viewDidDisappear中removeObserver把消息注銷掉。
三,在類的實例存在的時候接受消息。
很多時候,我們需要讓一些類的實例只要在內存中,就要接受消息,處理一些事情。比如我們有一個管理同步的類SyncManager,這個類使用了單例模式,從它alloc init之后就需要一些監聽同步的狀態,並作出處理。這個時候,我們就需要在重寫init函數,在其中注冊消息。
- (id) init
{
self = [super init];
if(self)
{
[[NSNotificationCenter defaultCenter] addObserver........]
}
return self;
}
然后在dealloc中注銷
- (void) dealloc
{
......
[ [NSNotificationCenter defaultCenter] removeObserver.......]
[super dealloc]
}
四,在viewController存在的時候接受消息
很多時候,我們會與ViewController打交道,甚至有些時候我們希望只要ViewController在內存中就監聽一些消息作出一些動作。剛開始的時候,我想實現這個功能,我是這么寫的
- (void) viewDidLoad
{
......
[[NSNotificationCenter defaultCenter] addObserver........]
.....
}
- (void) viewDidUnload
{
......
[ [NSNotificationCenter defaultCenter] removeObserver.......]
......
}
但是,在使用的過程中我發現viewDidLoad和Viewdidunload並不是成對出現的,只有在內存緊張和一些特定的情況下系統才會調用視圖的ViewDidUnload來卸載視圖。而ViewDIdload每一次加載都會執行。
也就是說removeObserver並不一定能夠被執行到,這就留下隱患。當視圖被dealloc之后,還在監聽消息。最終會造成程序的崩潰。而且有些時候如果沒有在unload中removeOberver還會造成多次注冊同一個消息。造成同一個函數執行多次。引起不必要的麻煩。
然后,在使用過程中,經過多次試驗我發現,使用init注冊消息並在dealloc注銷消息最為合適,就像第三條說的那樣。在這里值得提醒的一點是蘋果的官方文檔上說:
The notification center does not retain its observers, therefore, you must ensure that you unregister observers (using removeObserver: or removeObserver:name:object:) before they are deallocated. (If you don't, you will generate a runtime error if the center sends a message to a freed object.)
意思是NotificationCenter並不會對Observer進行retain操作。因為就沒有必要對observer做多余的release操作,而且,每一次注冊,必須對應一次注銷,不然,程序死翹翹的事情就會來了。