NSNotification顧名思義就是通知的作用,一個對象通知另外一個對象徘钥,可以用來傳遞參數(shù)、通信等作用离赫,與delegate的一對一不同芭逝,通知是一對多的。在一個對象中注冊了通知渊胸,那么其他任意對象都可以來對這個對象發(fā)出通知旬盯。
這篇文章主要講訴兩個對象
- NSNotificationCenter
- NSNotificationQueue
1、NSNotificationCenter
/**
* 注冊一個通知
*
*/
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getNotification:) name:@"notificationMethon" object:nil];
NSNotificationCenter是一個單列翎猛,我們可以通過defaultCenter來獲取到通知中心這個單列胖翰,使用通知的第一步就是添加通知。
/**
* 移除所有通知
*/
[[NSNotificationCenter defaultCenter] removeObserver:self];
/**
* 移除單個通知
*
*/
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"notificationMethon" object:nil];
需要注意的是當(dāng)我們添加一個通知以后切厘,必須在合適的位置將通知移除萨咳,不然下次再添加這個通知并調(diào)用時,這個通知將會被調(diào)用多次疫稿,而這一般不是我們所預(yù)料的培他。一般我們在對象的析構(gòu)函數(shù)中將通知移除,我們可以選擇將這個對象中的所有通知移除遗座,也可以選擇一個一個按照通知的name來移除舀凛。
/**
* 發(fā)出通知
*/
[[NSNotificationCenter defaultCenter] postNotificationName:@"notificationMethon" object:nil userInfo:@{@"key":@"value"}];
當(dāng)我們添加通知以后,我們就可以發(fā)出通知途蒋,也是通過NSNotificationCenter類的defaultCenter來獲取到通知中心猛遍,然后通過postNotificationName來發(fā)出通知。
這里需要注意的一點(diǎn)就是這樣發(fā)出的通知是同步操作号坡,也就是只有當(dāng)發(fā)出的通知執(zhí)行完畢以后才會繼續(xù)執(zhí)行接下去的代碼懊烤。
-(void)getNotification:(NSNotification *)info{
NSDictionary *dict = info.userInfo;
}
這是發(fā)出通知以后會調(diào)用的方法,在多線程操作時筋帖,發(fā)出通知的對象和接收通知的對象處于同一個線程奸晴。
在這個響應(yīng)的方法中有一個參數(shù)<code>(NSNotification *)info</code>這個參數(shù)是NSNotification類型的,這個類型有幾個屬性:
@property (readonly, copy) NSString *name;
@property (nullable, readonly, retain) id object;
@property (nullable, readonly, copy) NSDictionary *userInfo;
其中<code> userInfo </code>這個屬性是一個字典日麸,也是最為關(guān)鍵以及有用的屬性寄啼,我們通過這個屬性來傳遞參數(shù)等一些有用的信息。
總結(jié)以上內(nèi)容代箭,所以通知的最簡單的使用過程就是:
1墩划、添加通知;
2嗡综、發(fā)出通知乙帮;
3、移除通知极景;
2察净、NSNotificationQueue
上面說到<code> NSNotificationCenter</code>是一個同步操作驾茴,也就是只有當(dāng)響應(yīng)的通知的代碼執(zhí)行完畢以后,發(fā)出通知的對象的代碼才會繼續(xù)往下執(zhí)行氢卡。那么<code> NSNotificationQueue</code>就有一些區(qū)別锈至,他有兩個非常重要的特點(diǎn):即通告的聚結(jié)和異步發(fā)送。聚結(jié)是把和剛進(jìn)入隊(duì)列的通告相類似的其它通告從隊(duì)列中移除的過程译秦。如果一個新的通告和已經(jīng)在隊(duì)列中的通告相類似峡捡,則新的通告不進(jìn)入隊(duì)列,而所有類似的通告(除了隊(duì)列中的第一個通告以外)都被移除筑悴。然而们拙,您不應(yīng)該依賴于這個特殊的聚結(jié)行為。
而異步發(fā)送則很好理解了阁吝,也就是說發(fā)出通知以后立刻返回砚婆,也就是是繼續(xù)執(zhí)行下面的代碼,并不管通知發(fā)出后的具體情況
/**
發(fā)出通知
*/
NSNotification *notifacation = [[NSNotification alloc]initWithName:@"notificationMethon" object:nil userInfo:@{@"key":@"value1"}];
[[NSNotificationQueue defaultQueue] enqueueNotification:notifacation postingStyle:NSPostWhenIdle];
我們可以通過求摇,NSNotificationQueue的defaultQueue來獲取到這個通知隊(duì)列射沟,然后調(diào)用<code>enqueueNotification</code>來發(fā)出通知,我們可以看到第二個參數(shù)<code>postingStyle</code>,這個參數(shù)是一個枚舉与境,他可以是以下三個值:
typedef NS_ENUM(NSUInteger, NSPostingStyle) {
NSPostWhenIdle = 1,
NSPostASAP = 2,
NSPostNow = 3
};
這三個不同的值是有一定區(qū)別的验夯。(以下內(nèi)容摘抄自網(wǎng)絡(luò))
盡快發(fā)送
以NSPostASAP風(fēng)格進(jìn)入隊(duì)列的通告會在運(yùn)行循環(huán)的當(dāng)前迭代完成時被發(fā)送給通告中心,如果當(dāng)前運(yùn)行循環(huán)模式和請求的模式相匹配的話(如果請求的模式和當(dāng)前模式不同摔刁,則通告在進(jìn)入請求的模式時被發(fā)出)挥转。由于運(yùn)行循環(huán)在每個迭代過程中可能進(jìn)行多個調(diào)用分支(callout),所以在當(dāng)前調(diào)用分支退出及控制權(quán)返回運(yùn)行循環(huán)時共屈,通告可能被分發(fā)绑谣,也可能不被分發(fā)。其它的調(diào)用分支可能先發(fā)生拗引,比如定時器或由其它源觸發(fā)了事件借宵,或者其它異步的通告被分發(fā)了。
您通撤鳎可以將NSPostASAP風(fēng)格用于開銷昂貴的資源壤玫,比如顯示服務(wù)器。如果在運(yùn)行循環(huán)的一個調(diào)用分支過程中有很多客戶代碼在窗口緩沖區(qū)中進(jìn)行描畫哼凯,在每次描畫之后將緩沖區(qū)的內(nèi)容刷新到顯示服務(wù)器的開銷是很昂貴的欲间。在這種情況下,每個draw...方法都會將諸如“FlushTheServer” 這樣的通告排入隊(duì)列断部,并指定按名稱和對象進(jìn)行聚結(jié)猎贴,以及使用NSPostASAP風(fēng)格。結(jié)果,在運(yùn)行循環(huán)的最后她渴,那些通告中只有一個被派發(fā)达址,而窗口緩沖區(qū)也只被刷新一次。
空閑時發(fā)送
以NSPostWhenIdle風(fēng)格進(jìn)入隊(duì)列的通告只在運(yùn)行循環(huán)處于等待狀態(tài)時才被發(fā)出惹骂。在這種狀態(tài)下苏携,運(yùn)行循環(huán)的輸入通道中沒有任何事件,包括定時器和異步事件对粪。以NSPostWhenIdle風(fēng)格進(jìn)入隊(duì)列的一個典型的例子是當(dāng)用戶鍵入文本、而程序的其它地方需要顯示文本字節(jié)長度的時候装蓬。在用戶輸入每一個字符后都對文本輸入框的尺寸進(jìn)行更新的開銷是很大的(而且不是特別有用)著拭,特別是當(dāng)用戶快速輸入的時候。在這種情況下牍帚,Cocoa會在每個字符鍵入之后儡遮,將諸如“ChangeTheDisplayedSize”這樣的通告進(jìn)行排隊(duì),同時把聚結(jié)開關(guān)打開暗赶,并使用NSPostWhenIdle風(fēng)格鄙币。當(dāng)用戶停止輸入的時候,隊(duì)列中只有一個“ChangeTheDisplayedSize”通告(由于聚結(jié)的原因)會在運(yùn)行循環(huán)進(jìn)入等待狀態(tài)時被發(fā)出蹂随,顯示部分也因此被刷新十嘿。請注意,運(yùn)行循環(huán)即將退出(當(dāng)所有的輸入通道都過時的時候岳锁,會發(fā)生這種情況)時并不處于等待狀態(tài)绩衷,因此也不會發(fā)出通告。
立即發(fā)送
以NSPostNow風(fēng)格進(jìn)入隊(duì)列的通告會在聚結(jié)之后激率,立即發(fā)送到通告中心咳燕。您可以在不需要異步調(diào)用行為的時候 使用NSPostNow風(fēng)格(或者通過NSNotificationCenter的postNotification:方法來發(fā)送)。在很多編程環(huán)境下乒躺,我們不僅允許同步的行為招盲,而且希望使用這種行為:即您希望通告中心在通告派發(fā)之后返回,以便確定觀察者對象收到通告并進(jìn)行了處理嘉冒。當(dāng)然曹货,當(dāng)您希望通過聚結(jié)移除隊(duì)列中類似的通告時,應(yīng)該用enqueueNotification...方法健爬,且使用NSPostNow風(fēng)格控乾,而不是使用postNotification:方法。
總結(jié)NSNotificationCenter和NSNotificationQueue的區(qū)別娜遵,也許最大的一點(diǎn)就是發(fā)出通知時一個是同步一個是異步蜕衡。
如果對您有一定幫助,請關(guān)注本人。
(轉(zhuǎn)載請表明出處慨仿、作者)