詳解Cocoa中監(jiān)聽、觀察和通知五種方法
Cocoa中監(jiān)聽、觀察和通知五種方法是本文要介紹的內(nèi)容,本文介紹Objective C中實(shí)現(xiàn)觀察者模式(也被稱為廣播者/監(jiān)聽者、發(fā)布/注冊或者通知)的五種方法以及每種方法的價(jià)值所在。該文章將包括:
1、手動(dòng)廣播者和監(jiān)聽者(Broadcaster and listeners)
2、鍵-值觀察(Key Value Observing)
3、通知中心(Notification center)
4、上下文通知(Context notification)
5、用于觀察的委托(Delegate)
關(guān)于觀察者
觀察者模式是維持兩個(gè)模塊之間抽象關(guān)系的***大的方式之一。觀察者模式包括一個(gè)發(fā)布已發(fā)生事件的模塊以及響應(yīng)該事件的另一模塊的若干個(gè)的實(shí)例。它和直接調(diào)用第二個(gè)模塊的方法不同,因?yàn)?**個(gè)模塊不需要關(guān)注有多少個(gè)觀察者,從而實(shí)現(xiàn)觀察者和被觀察者之間更加完全的抽象關(guān)系。
手動(dòng)廣播者和監(jiān)聽者
手動(dòng)的方式需要廣播者保有一個(gè)監(jiān)聽者的數(shù)組(NSArray)或集合(NSSet)。在需要通知監(jiān)聽者一個(gè)事件的合適時(shí)機(jī)廣播者直接調(diào)用各個(gè)監(jiān)聽者上相關(guān)方法。
在廣播者類上你可能需要一個(gè)NSMutableArray、NSSet或NSMutableDictionary。NSMutableDictionary比較適合將事件標(biāo)識符的類型作為每個(gè)監(jiān)聽者的鍵值。在廣播者上你還需要有監(jiān)聽者注冊和取消注冊的方法。
給NSArray或NSSet中的每個(gè)對象方式消息的方法很簡單,如下:
- [listenersCollection makeObjectsPerformSelector:@selector(methodSupportedByEveryListener)];
更多信息參見: Collections Programming Topics for Cocoa
優(yōu)點(diǎn): 廣播者對監(jiān)聽者列表有完全的控制。
缺點(diǎn): 在集合中手動(dòng)添加或移除監(jiān)聽者(尤其是在由于其他原因已經(jīng)不被維護(hù)的情況下)。如果需要發(fā)布不同消息的情況下就需要更多的手動(dòng)工作。
鍵值觀察
鍵值觀察協(xié)議時(shí)朝著自動(dòng)化如上過程方向的一個(gè)很大進(jìn)步。在很多情況下,廣播者不需要做任何事情。
每個(gè)Cocoa對象自動(dòng)處理用于發(fā)布任何對象的addObserver:forKeyPath:options:context:。如果廣播者的“setter”方法遵循某些規(guī)則,“setter”方法就會(huì)自動(dòng)觸發(fā)任何監(jiān)聽者的observeValueForKeyPath:ofObject:change:context:方法。
例如如下代碼就會(huì)在“source”對象上加入一個(gè)觀察者::
- [source addObserver:destination
- forKeyPath:@"myValue" options:NSKeyValueChangeNewKey
- context:nil];
這樣在每次調(diào)用setMyValue:方法的時(shí)候都會(huì)發(fā)送一個(gè)observeValueForKeyPath:ofObject:change:context:消息到destination。
你所需要做的就是在被觀察對象上注冊監(jiān)聽者并讓監(jiān)聽者實(shí)現(xiàn)
- observeValueForKeyPath:ofObject:change:context:
更多信息參見:NSKeyValueObserving Protocol Reference
優(yōu)點(diǎn): 內(nèi)置的而且是自動(dòng)的??梢杂^察任何鍵路徑。支持依賴通知。
缺點(diǎn): 廣播者無法知道誰在監(jiān)聽。方法必須符合命名規(guī)則以實(shí)現(xiàn)自動(dòng)觀察消息的運(yùn)作。監(jiān)聽者必須在被刪除之前被移除,否者接下來的通知就會(huì)導(dǎo)致崩潰和失效-不過這對于該文中指出的所有方法都是一樣的。
通知中心
NSNotificationCenter提供了一種更加解耦的方式。最典型的應(yīng)用就是任何對象對可以發(fā)送通知到中心,同時(shí)任何對象可以監(jiān)聽中心的通知。
發(fā)送通知的代碼如下:
- [[NSNotificationCenter defaultCenter]
- postNotificationName:@"myNotificationName" object:broadcasterObject];
注冊接收通知的代碼如下:
- [[NSNotificationCenter defaultCenter] addObserver:listenerObject
- selector:@selector(receivingMethodOnListener:) name:@"myNotificationName" object:nil];
注冊通知的時(shí)候可以指定一個(gè)具體的廣播者對象,但這不是必須的。你可能注意到了defaultCenter 。實(shí)際上這是你在應(yīng)用中會(huì)使用到的唯一的中心。通知會(huì)向整個(gè)應(yīng)用開放,因此只有一個(gè)中心。
同時(shí)還有一個(gè)NSDistributedNotificationCenter。這是用來應(yīng)用間通信的。在整個(gè)計(jì)算機(jī)上只有一個(gè)該類型的中心。
更多信息請參見:Notification Programming Topics for Cocoa
優(yōu)點(diǎn): 通知的發(fā)送者和接受者都不需要知道對方。可以指定接收通知的具體方法。通知名可以是任何字符串。
缺點(diǎn): 較鍵值觀察需要多點(diǎn)代碼。在刪掉前必須移除監(jiān)聽者。
上下文通知
如果被觀察屬性是一個(gè)NSManagedOjbect的聲明屬性,就可以監(jiān)聽
- NSManagedObjectContextObjectsDidChangeNotification
這仍然使用NSNotification方式不過有點(diǎn)不同,因?yàn)镹SManagedObject不會(huì)手動(dòng)發(fā)送通知。
這種方法的注冊如下
- [[NSNotificationCenter defaultCenter]
- addObserver:listenerObejct selector:@selector(receivingMethodOnListener:)
- name:NSManagedObjectContextObjectsDidChangeNotification
- object:observedManagedObjectContext];
在receivingMethodOnListener:中,通知的userinfo中NSInsertedObjectsKey、NSUpdatedObjectsKey和NSDeletedObjectsKey等鍵值會(huì)給出受影響的對象集合。
更多信息請參見NSManagedObjectContext Class Reference
優(yōu)點(diǎn): 是在整個(gè)NSManagedObjectContext中跟蹤變化的最簡單的方式。
缺點(diǎn): 僅適用于Core Data并不能提供影響對象之外的具體信息。用于觀察的委托
***一個(gè)Cocoa簡化的觀察者模式是委托。廣義上說委托可以不僅僅處理簡單的觀察,但不一定需要做更多。 比如,NSApplication和NSWindow所有的通知都會(huì)同時(shí)傳給委托并由其處理。有些類會(huì)傳給它們的委托類似通知的消息,而不同時(shí)發(fā)送通知。比如NSMenu,發(fā)送menuWillOpen:給其委托但不會(huì)發(fā)送相應(yīng)的NSNotification。 為了連接一個(gè)委托,只需在支持委托的對象上調(diào)用如下代碼:
- [object setDelegate:delegateObject];
對象可以收到任何它想要的委托消息。
更多信息請參見:Cocoa Fundamentals Guide: Delegates and Data Sources
優(yōu)點(diǎn): 支持它的類有詳盡和具體信息。
缺點(diǎn): 該類必須支持委托。某一時(shí)間只能有一個(gè)委托連接到某一對象。
小結(jié):詳解Cocoa中監(jiān)聽、觀察和通知五種方法的內(nèi)容介紹完了,希望通過本文的學(xué)習(xí)能對你有所幫助!