25. 什么時候用delegate,什么時候用Notification?
1、Delegate是一種點對點的消息傳送機制。傳遞給自己或者其他對象。有時候他還會返回一個影響事件如何被處理的值。
舉一個簡單的Mac例子,NSWindow聲明了有一個名叫windowShouldClose:的協議,當用戶點窗口左上角的關閉按鈕時,這個窗口對象就會發送一個windowShouldClose:消息給他的delegate,來詢問這個窗口是否可以被關閉。這個delegate會返回一個boolean值,來控制窗口對象的這個(關閉)行為。
2、Notification是一種一對多的消息傳遞方式。他的實質是廣播信息給所有observer。
消息發送者不需要知道誰是消息的接收者。
Delegate:
消息的發送者(sender)告知接收者(receiver)某個事件將要發生,delegate同意然然后發送者響應事件,delegate機制使得接收者可以改變發送者的行為。通常發送者和接收者的關系是直接的一對多的關系。
Notification:
消息的發送者告知接收者事件已經發生或者將要發送,僅此而已,接收者并不能反過來影響發送者的行為。通常發送者和接收者的關系是間接的多對多關系。
1、什么是Notification?
答:觀察者模式,controller向defaultNotificationCenter添加自己的 notification,其他類注冊這個notification就可以收到通知,這些類可以在收到通知時做自己的操作(多觀察者默認隨機順序發通知給 觀察者們,而且每個觀察者都要等當前的某個觀察者的操作做完才能輪到他來操作,可以用NotificationQueue的方式安排觀察者的反應順序,也 可以在添加觀察者中設定反映時間,取消觀察需要在viewDidUnload 跟dealloc中都要注銷)。
2、什么時候用delegate,什么時候用Notification?
答:delegate針對one-to-one關系,并且reciever可以返回值給 sender,notification 可以針對one-to-one/many/none,reciever無法返回值給sender.所以,delegate用于sender希望接受到 reciever的某個功能反饋值,notification用于通知多個object某個事件。
Notification:
通知模式:一個對象能夠給其他任意數量的對象廣播信息。對象之間可以沒有耦合關系。
NSNotification(通知),封裝了要廣播的信息。 NSNotificationCenter(通知中?心),管理注冊接收消息對象,廣播消息。 observer(觀察者),需要監測廣播信息的對象,即接收信息的對象。
http://www.lxweimin.com/p/6107494426e4
http://www.lxweimin.com/p/393920b15539
NSNotification原理簡析
NSNotification使用的是同步操作。即如果你在程序中的A位置post了一個NSNotification,在B位置注冊了一個observer,通知發出后,必須等到B位置的通知回調執行完以后才能返回到A處繼續往下執行。因此,不要過多的或者低效的使用NSNotification,推薦的方式是通過一些“中間的”觀察者將通告的結果傳遞給它們可以訪問的對象。
如果想讓NSNotification的post處和observer處異步執行,可以通過NSNotificationQueue實現。
對于同一個通知,如果注冊了多個觀察者,則這多個觀察者的執行順序和他們的注冊順序是保持一致的。
NSNotification線程
NSNotificationCenter在轉發NSNotification消息的時候,在哪個線程中post,就在哪個線程中轉發。換句話說,不管你的observer是在哪個線程,observer的回調方法執行線程都和post的線程保持一致。
如果想讓post的線程和轉發的線程不同,可以通過NSNotification重定向技術實現。
作者:吳白
鏈接:http://www.lxweimin.com/p/393920b15539
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
http://www.cnblogs.com/xiaouisme/archive/2012/04/06/2434753.html
通告中心同步地將通告派發給它的觀察者。發出通告的對象直到所有的通告被發出后,才重新獲得程序的控制權。如果需要以異步的方式發送通告,必須使用通告隊列。
NSNotificationCenter
每個任務都有一個缺省的通告中心,您可以通過NSNotificationCenter的defaultCenter類方法來進行訪問。通告中心在單任務中處理通告。如果需要在同一個機器的不同任務之間進行通訊,可以使用分布式通告中心。
通告中心同步地將通告發送給觀察者。換句話說,在發出一個通告時,在所有的觀察者接收和處理完成通告之前,程序的控制權不會返回給發送者。如果需要異步發送通告,可以使用通告隊列,這在"通告隊列"部分中進行描述。
在多線程的應用程序中,通告總是在發送的線程中傳送,這個線程可能不同于觀察者注冊所在的線程。
NSDistributedNotificationCenter
每個任務都有一個缺省的分布式通告中心,您可以通過NSDistributedNotificationCenter的defaultCenter類方法來訪問。這個分布式通告中心負責處理同一個機器的不通任務之間的通告。如果需要實現不同機器上的任務間通訊,請使用分布式對象。
發送分布式通告是一個開銷昂貴的操作。通告會被發送給一個系統級別的服務器,然后再分發到注冊了該分布式通告的對象所在的任務中。發送通告和通告到達另一個任務之間的延遲是很大的。事實上,如果發出的通告太多,以致于充滿了服務器的隊列,就可能被丟棄。
分布式通告通過任務的運行循環來分發。任務必須運行在某種“常見”模式的運行循環下,比如NSDefaultRunLoopMode模式,才能接收分布式通告。如果接收通告的任務是多線程的,則不要以通告會到達主線程作為前提。通告通常被分發到主線程的運行循環上,但是其它線程也可以接收通告。
盡管常規的通告中心允許任何對象作為通告對象(也就是通告封裝的對象),分布式通告中心只支持將NSString對象作為它的通告對象。由于發出通告的對象和通告的觀察者可能位于不同的任務中,通告不能包含指向任意對象的指針。因此,分布式通告中心要求通告使用字符串作為通告對象。通告的匹配就是基于這個字符串進行的,而不是基于對象指針。
通告隊列
NSNotificationQueue對象(或者簡單稱為通告隊列)的作用是充當通告中心(NSNotificationCenter的實例)的緩沖區。通告隊列通常以先進先出(FIFO)的順序維護通告。當一個通告上升到隊列的前面時,隊列就將它發送給通告中心,通告中心隨后將它派發給所有注冊為觀察者的對象。
每個線程都有一個缺省的通告隊列,與任務的缺省通告中心相關聯。圖5-9展示了這種關聯。您可以創建自己的通告隊列,使得每個線程和通告中心有多個隊列。
聚結的通告
NSNotificationQueue類為Foundation Kit的通告機制增加了兩個重要的特性:即通告的聚結和異步發送。聚結是把和剛進入隊列的通告相類似的其它通告從隊列中移除的過程。如果一個新的通告和已經在隊列中的通告相類似,則新的通告不進入隊列,而所有類似的通告(除了隊列中的第一個通告以外)都被移除。然而,您不應該依賴于這個特殊的聚結行為。
您可以為enqueueNotification:postingStyle:coalesceMask:forModes:方法的第三個參數指定如下的一或多個常量,指示簡化的條件:
NSNotificationNoCoalescing
NSNotificationCoalescingOnName
NSNotificationCoalescingOnSender
您可以對NSNotificationCoalescingOnName和NSNotificationCoalescingOnSender常量進行位或操作,指示Cocoa同時使用通告名稱和通告對象進行聚結。那樣的話,和剛剛進入隊列的通告具有相同名稱和發送者對象的所有通告都會被聚結。
異步發送通告
通過NSNotificationCenter類的postNotification:方法及其變體,您可以將通告立即發送給通告中心。但是,這個方法的調用是同步的:即在通告發送對象可以繼續執行其所在線程的工作之前,必須等待通告中心將通告派發給所有的觀察者并將控制權返回。但是,您也可以通過NSNotificationQueue的enqueueNotification:postingStyle:和enqueueNotification:postingStyle:coalesceMask:forModes:方法將通告放入隊列,實現異步發送,在把通告放入隊列之后,這些方法會立即將控制權返回給調用對象。
Cocoa根據排隊方法中指定的發送風格和運行循環模式來清空通告隊列和發送通告。模式參數指定在什么運行循環模式下清空隊列。舉例來說,如果您指定NSModalPanelRunLoopMode模式,則通告只有當運行循環處于該模式下才會被發送。如果當前運行循環不在該模式下,通告就需要等待,直到下次運行循環進入該模式。
向通告隊列發送通告可以有三種風格:NSPostASAP、NSPostWhenIdle、和NSPostNow,這些風格將在接下來的部分中進行說明。
盡快發送
以NSPostASAP風格進入隊列的通告會在運行循環的當前迭代完成時被發送給通告中心,如果當前運行循環模式和請求的模式相匹配的話(如果請求的模式和當前模式不同,則通告在進入請求的模式時被發出)。由于運行循環在每個迭代過程中可能進行多個調用分支(callout),所以在當前調用分支退出及控制權返回運行循環時,通告可能被分發,也可能不被分發。其它的調用分支可能先發生,比如定時器或由其它源觸發了事件,或者其它異步的通告被分發了。
您通??梢詫SPostASAP風格用于開銷昂貴的資源,比如顯示服務器。如果在運行循環的一個調用分支過程中有很多客戶代碼在窗口緩沖區中進行描畫,在每次描畫之后將緩沖區的內容刷新到顯示服務器的開銷是很昂貴的。在這種情況下,每個draw...方法都會將諸如“FlushTheServer” 這樣的通告排入隊列,并指定按名稱和對象進行聚結,以及使用NSPostASAP風格。結果,在運行循環的最后,那些通告中只有一個被派發,而窗口緩沖區也只被刷新一次。
空閑時發送
以NSPostWhenIdle風格進入隊列的通告只在運行循環處于等待狀態時才被發出。在這種狀態下,運行循環的輸入通道中沒有任何事件,包括定時器和異步事件。以NSPostWhenIdle風格進入隊列的一個典型的例子是當用戶鍵入文本、而程序的其它地方需要顯示文本字節長度的時候。在用戶輸入每一個字符后都對文本輸入框的尺寸進行更新的開銷是很大的(而且不是特別有用),特別是當用戶快速輸入的時候。在這種情況下,Cocoa會在每個字符鍵入之后,將諸如“ChangeTheDisplayedSize”這樣的通告進行排隊,同時把聚結開關打開,并使用NSPostWhenIdle風格。當用戶停止輸入的時候,隊列中只有一個“ChangeTheDisplayedSize”通告(由于聚結的原因)會在運行循環進入等待狀態時被發出,顯示部分也因此被刷新。請注意,運行循環即將退出(當所有的輸入通道都過時的時候,會發生這種情況)時并不處于等待狀態,因此也不會發出通告。
立即發送
以NSPostNow風格進入隊列的通告會在聚結之后,立即發送到通告中心。您可以在不需要異步調用行為的時候 使用NSPostNow風格(或者通過NSNotificationCenter的postNotification:方法來發送)。在很多編程環境下,我們不僅允許同步的行為,而且希望使用這種行為:即您希望通告中心在通告派發之后返回,以便確定觀察者對象收到通告并進行了處理。當然,當您希望通過聚結移除隊列中類似的通告時,應該用enqueueNotification...方法,且使用NSPostNow風格,而不是使用postNotification:方法。