Notification Center的概念:
它是一個(gè)單例對(duì)象,允許當(dāng)事件發(fā)生時(shí)通知一些對(duì)象,讓對(duì)象做出相應(yīng)反應(yīng)。
它允許我們?cè)诘统潭锐詈系那闆r下,滿足控制器與一個(gè)任意的對(duì)象進(jìn)行通信的目的。 這種模式的基本特征是為了讓其他的對(duì)象能夠接收到某種事件傳遞過(guò)來(lái)的通知,主要使用通知名稱來(lái)發(fā)送和接收通知。
基本上不用考慮其它影響因素,只需要使用同樣的通知名稱,監(jiān)聽(tīng)該通知的對(duì)象(即觀察者)再對(duì)通知做出反應(yīng)即可。
優(yōu)勢(shì):
1.不需要編寫(xiě)多少代碼,實(shí)現(xiàn)比較簡(jiǎn)單;
2.對(duì)于一個(gè)發(fā)出的通知,多個(gè)對(duì)象能夠做出反應(yīng),簡(jiǎn)單實(shí)現(xiàn)1對(duì)多的方式,較之于 Delegate 可以實(shí)現(xiàn)更大的跨度的通信機(jī)制;
3.能夠傳遞參數(shù)(object和userInfo),object和userInfo可以攜帶發(fā)送通知時(shí)傳遞的信息。
缺點(diǎn):
1.在編譯期間不會(huì)檢查通知是否能夠被觀察者正確的處理;
2.在釋放通知的觀察者時(shí),需要在通知中心移除觀察者;
3.在調(diào)試的時(shí)候,通知傳遞的過(guò)程很難控制和跟蹤;
4.發(fā)送通知和接收通知時(shí)需要提前知道通知名稱,如果通知名稱不一致,會(huì)出現(xiàn)不同步的情況;
5.通知發(fā)出后,不能從觀察者獲得任何的反饋信息。
<一>NSNotification 一般使用情況的的5種使用方式
1、不傳遞參數(shù), 最常用的一種
/*----------------------- 一 --------- 不傳遞參數(shù), 最常用的一種 ------------------------------------*/
// 第一步:監(jiān)聽(tīng)通知
- (void)ListeningToNotification1{
//監(jiān)聽(tīng)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(noti1) name:@"noti1" object:nil];
}
// 第二部:發(fā)送通知
-(void)btn1Click{
[[NSNotificationCenter defaultCenter] postNotificationName:@"noti1" object:nil];
}
//調(diào)用方法
-(void)noti1{
NSLog(@"接收 不帶參數(shù)的消息");
}
2、 使用監(jiān)聽(tīng)一方的調(diào)用方法時(shí) 傳遞消息
//發(fā)通知
/*--------------- 二 ------ 使用監(jiān)聽(tīng)一方的調(diào)用方法時(shí) 傳遞消息-------------*/
// 第一步:監(jiān)聽(tīng)通知
- (void)ListeningToNotification2{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(noti2:) name:@"noti2" object:nil];
}
// 第二部:發(fā)送通知(可以跨控制器進(jìn)行發(fā)送)
-(void)btn2Click:(UIButton *)btn
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"noti2" object:[NSString stringWithFormat:@"%@",btn.titleLabel.text]];
}
//調(diào)用方法
-(void)noti2:(NSNotification *)noti
{
//使用object處理消息
NSString *info = [noti object];
NSLog(@"接收 object傳遞的消息:%@",info);
}
3、使用發(fā)送通知一方的 userInfo 傳遞消息
/*----------- 三 ----------- 使用發(fā)送通知一方的userInfo 傳遞消息 ----------*/
// 第一步:監(jiān)聽(tīng)通知
-(void)ListeningToNotification3{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(noti3:) name:@"noti3" object:nil];
}
//第二步:發(fā)送通知
-(void)btn3Click{
NSDictionary *dic = [NSDictionary dictionaryWithObject:@"wangLei在這里" forKey:@"param"];
// 我把方法的object都設(shè)為了nil。那么這個(gè)參數(shù)起到什么作用呢?這個(gè)參數(shù)有點(diǎn)像二次確認(rèn)的意思,就是在同一個(gè)通知name的情況下還可以通過(guò)object再次進(jìn)行細(xì)分通知。就拿上面這個(gè)小demo說(shuō),如果object為空,接收方會(huì)接受所有名字為giveName的通知。但是如果object不為空,接收方就會(huì)只接收名字為giveName的而且object正確的通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"noti3" object:nil userInfo:dic];
}
//調(diào)用方法
-(void)noti3:(NSNotification *)noti
{
//使用userInfo處理消息
NSDictionary *dic = [noti userInfo];
NSString *info = [dic objectForKey:@"param"];
NSLog(@"接收 userInfo傳遞的消息:%@",info);
}
// 最后一步:移除通知
-(void)dealloc
{
//移除觀察者,Observer不能為nil
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
4 :使用block接收通知,不用再指定方法了
//第一步:接收通知
- (void)ListeningToNotification4{
[[NSNotificationCenter defaultCenter]addObserverForName:@"noti4" object:nil queue:nil usingBlock:^(NSNotification *not){
//使用userInfo處理消息
NSDictionary *dic = [not userInfo];
NSString *info = [dic objectForKey:@"param"];
NSLog(@"使用block接收傳遞的消息:%@",info);
}];
}
//第二步:發(fā)送通知
-(void)btn4Click{
NSDictionary *dic = [NSDictionary dictionaryWithObject:@"wangLei" forKey:@"param"];
// 我把方法的object都設(shè)為了nil。那么這個(gè)參數(shù)起到什么作用呢?這個(gè)參數(shù)有點(diǎn)像二次確認(rèn)的意思,就是在同一個(gè)通知name的情況下還可以通過(guò)object再次進(jìn)行細(xì)分通知。就拿上面這個(gè)小demo說(shuō),如果object為空,接收方會(huì)接受所有名字為giveName的通知。但是如果object不為空,接收方就會(huì)只接收名字為giveName的而且object正確的通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"noti4" object:nil userInfo:dic];
}
5、使用NSNotificationQueue實(shí)現(xiàn)通知的異步
// 第一步:注冊(cè)通知
- (void)ListeningToNotification5{
/**
* 注冊(cè)一個(gè)通知
*
*/
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getNotification:) name:@"notificationMethon" object:nil];
}
//第二部: 發(fā)出通知
- (void)btn5Click{
// [[NSNotificationCenter defaultCenter] postNotificationName:@"notificationMethon" object:nil userInfo:@{@"key":@"value"}];
NSNotification *notifacation = [[NSNotification alloc]initWithName:@"notificationMethon" object:nil userInfo:@{@"key":@"value1"}];
[[NSNotificationQueue defaultQueue] enqueueNotification:notifacation postingStyle:NSPostNow];
/*
我們可以通過(guò),NSNotificationQueue的defaultQueue來(lái)獲取到這個(gè)通知隊(duì)列,然后調(diào)用enqueueNotification來(lái)發(fā)出通知,我們可以看到第二個(gè)參數(shù)postingStyle,這個(gè)參數(shù)是一個(gè)枚舉,他可以是以下三個(gè)值:
typedef NS_ENUM(NSUInteger, NSPostingStyle) {
NSPostWhenIdle = 1,
NSPostASAP = 2,
NSPostNow = 3
};
這三個(gè)不同的值是有一定區(qū)別的。(以下內(nèi)容摘抄自網(wǎng)絡(luò))
盡快發(fā)送
以NSPostASAP風(fēng)格進(jìn)入隊(duì)列的通告會(huì)在運(yùn)行循環(huán)的當(dāng)前迭代完成時(shí)被發(fā)送給通
告中心,如果當(dāng)前運(yùn)行循環(huán)模式和請(qǐng)求的模式相匹配的話(如果請(qǐng)求的模式和當(dāng)
前模式不同,則通告在進(jìn)入請(qǐng)求的模式時(shí)被發(fā)出)。由于運(yùn)行循環(huán)在每個(gè)迭代過(guò)
程中可能進(jìn)行多個(gè)調(diào)用分支(callout),所以在當(dāng)前調(diào)用分支退出及控制權(quán)返回
運(yùn)行循環(huán)時(shí),通告可能被分發(fā),也可能不被分發(fā)。其它的調(diào)用分支可能先發(fā)生
,比如定時(shí)器或由其它源觸發(fā)了事件,或者其它異步的通告被分發(fā)了。
您通??梢詫SPostASAP風(fēng)格用于開(kāi)銷(xiāo)昂貴的資源,比如顯示服務(wù)器。如果在
運(yùn)行循環(huán)的一個(gè)調(diào)用分支過(guò)程中有很多客戶代碼在窗口緩沖區(qū)中進(jìn)行描畫(huà),在每
次描畫(huà)之后將緩沖區(qū)的內(nèi)容刷新到顯示服務(wù)器的開(kāi)銷(xiāo)是很昂貴的。在這種情況
下,每個(gè)draw...方法都會(huì)將諸如“FlushTheServer” 這樣的通告排入隊(duì)列,并指定
按名稱和對(duì)象進(jìn)行聚結(jié),以及使用NSPostASAP風(fēng)格。結(jié)果,在運(yùn)行循環(huán)的最
后,那些通告中只有一個(gè)被派發(fā),而窗口緩沖區(qū)也只被刷新一次。
空閑時(shí)發(fā)送
以NSPostWhenIdle風(fēng)格進(jìn)入隊(duì)列的通告只在運(yùn)行循環(huán)處于等待狀態(tài)時(shí)才被發(fā)
出。在這種狀態(tài)下,運(yùn)行循環(huán)的輸入通道中沒(méi)有任何事件,包括定時(shí)器和異步事
件。以NSPostWhenIdle風(fēng)格進(jìn)入隊(duì)列的一個(gè)典型的例子是當(dāng)用戶鍵入文本、而
程序的其它地方需要顯示文本字節(jié)長(zhǎng)度的時(shí)候。在用戶輸入每一個(gè)字符后都對(duì)文
本輸入框的尺寸進(jìn)行更新的開(kāi)銷(xiāo)是很大的(而且不是特別有用),特別是當(dāng)用戶
快速輸入的時(shí)候。在這種情況下,Cocoa會(huì)在每個(gè)字符鍵入之后,將諸
如“ChangeTheDisplayedSize”這樣的通告進(jìn)行排隊(duì),同時(shí)把聚結(jié)開(kāi)關(guān)打開(kāi),并使
用NSPostWhenIdle風(fēng)格。當(dāng)用戶停止輸入的時(shí)候,隊(duì)列中只有一
個(gè)“ChangeTheDisplayedSize”通告(由于聚結(jié)的原因)會(huì)在運(yùn)行循環(huán)進(jìn)入等待狀
態(tài)時(shí)被發(fā)出,顯示部分也因此被刷新。請(qǐng)注意,運(yùn)行循環(huán)即將退出(當(dāng)所有的輸
入通道都過(guò)時(shí)的時(shí)候,會(huì)發(fā)生這種情況)時(shí)并不處于等待狀態(tài),因此也不會(huì)發(fā)出
通告。
立即發(fā)送
以NSPostNow風(fēng)格進(jìn)入隊(duì)列的通告會(huì)在聚結(jié)之后,立即發(fā)送到通告中心。您可以
在不需要異步調(diào)用行為的時(shí)候 使用NSPostNow風(fēng)格(或者通過(guò)
NSNotificationCenter的postNotification:方法來(lái)發(fā)送)。在很多編程環(huán)境下,我
們不僅允許同步的行為,而且希望使用這種行為:即您希望通告中心在通告派發(fā)
之后返回,以便確定觀察者對(duì)象收到通告并進(jìn)行了處理。當(dāng)然,當(dāng)您希望通過(guò)聚
結(jié)移除隊(duì)列中類(lèi)似的通告時(shí),應(yīng)該用enqueueNotification...方法,且使用
NSPostNow風(fēng)格,而不是使用postNotification:方法。
*/
}
//
-(void)getNotification:(NSNotification *)info{
NSDictionary *dict = info.userInfo;
NSLog(@"當(dāng)前執(zhí)行任務(wù)的線程為%@",[NSThread currentThread]);
}
// 第三部:我們將調(diào)用發(fā)出通知的代碼放在一個(gè)非主隊(duì)列里面
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
[self btn5Click];
[NSThread sleepForTimeInterval:3];
NSLog(@"1目前的queue所在的線程為%@",[NSThread currentThread]);
}];
運(yùn)行結(jié)果如下:
2017-02-20 16:14:53.217 NSNotificationDemo[6438:492325] 這是通知后面的代碼,按照通知是同步的道理,應(yīng)該在通知完成回調(diào)之后才會(huì)執(zhí)行
2017-02-20 16:14:53.219 NSNotificationDemo[6438:493599] 這是通知里面執(zhí)行的代碼,這里的代碼正常情況下要執(zhí)行完之后,才能執(zhí)行通知之后的代碼;當(dāng)前執(zhí)行任務(wù)的線程為<NSThread: 0x600000077880>{number = 3, name = (null)}
2017-02-20 16:14:56.222 NSNotificationDemo[6438:493599] 1目前的queue所在的線程為<NSThread: 0x600000077880>{number = 3, name = (null)}
記住下面的話:
上面說(shuō)到 NSNotificationCenter是一個(gè)同步操作,也就是只有當(dāng)響應(yīng)的通知的代碼執(zhí)行完畢以后,發(fā)出通知的對(duì)象的代碼才會(huì)繼續(xù)往下執(zhí)行。
那么 NSNotificationQueue就有一些區(qū)別,他有兩個(gè)非常重要的特點(diǎn):即通告的聚結(jié)和異步發(fā)送。聚結(jié)是把和剛進(jìn)入隊(duì)列的通告相類(lèi)似的其它通告從隊(duì)列中移除的過(guò)程。如果一個(gè)新的通告和已經(jīng)在隊(duì)列中的通告相類(lèi)似,則新的通告不進(jìn)入隊(duì)列,而所有類(lèi)似的通告(除了隊(duì)列中的第一個(gè)通告以外)都被移除。然而,您不應(yīng)該依賴于這個(gè)特殊的聚結(jié)行為。
而異步發(fā)送則很好理解了,也就是說(shuō)發(fā)出通知以后立刻返回,也就是是繼續(xù)執(zhí)行下面的代碼,并不管通知發(fā)出后的具體情況
總結(jié)NSNotificationCenter和NSNotificationQueue的區(qū)別,也許最大的一點(diǎn)就是發(fā)出通知時(shí)一個(gè)是同步一個(gè)是異步。
最后,記得在發(fā)送通知消息的頁(yè)面,在dealloc方法里面移除觀察者。
-(void)dealloc
{
//移除觀察者,Observer不能為nil
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
<二>NSNotification 添加本地通知的使用方式
demo2下載地址
<1>、本地通知欄通知
1.1、本地通知的創(chuàng)建和使用
本地通知其實(shí)在之前的文章和網(wǎng)上就已經(jīng)很詳細(xì)的說(shuō)了,主要是UILocalNotification的使用,本地通知主要應(yīng)用在固定時(shí)間的通知事件,比如日歷、活動(dòng)提醒等
NSLog(@"添加本地通知");
//ios8.0以上的系統(tǒng)需要注冊(cè)通知
if (D_ISHight(8.0)) {
//注冊(cè)通知
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeSound|UIUserNotificationTypeBadge categories:nil]];
}
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
//設(shè)置固定時(shí)間通知
if (sender.tag == LOCALNOTIFICATION1) {
NSDateFormatter * forma = [[NSDateFormatter alloc] init];
[forma setDateFormat:@"HH:mm"];
localNotification.fireDate = [forma dateFromString:@"13:20"]; //12點(diǎn)提醒
[localNotification setRepeatInterval:NSCalendarUnitDay]; //每天12點(diǎn)
}
//設(shè)置重復(fù)間隔時(shí)間
// else if (sender.tag == LOCALNOTIFICATION1){
// NSDate *date =[[NSDate alloc] init];
// localNotification.fireDate = [date dateByAddingTimeInterval:5];//重復(fù)間隔的時(shí)長(zhǎng)
// [localNotification setRepeatInterval:NSCalendarUnitSecond];//時(shí)間間隔單位,秒
// }
[localNotification setTimeZone:[NSTimeZone defaultTimeZone]]; //時(shí)區(qū)
//ios8.2以上的系統(tǒng)可以設(shè)置標(biāo)題
if (D_ISHight(8.2)) {
[localNotification setAlertTitle:@"提醒標(biāo)題"];
}
[localNotification setAlertBody:@"提醒內(nèi)容:Damon"];
[localNotification setAlertAction:@"鎖屏?xí)r顯示的動(dòng)作標(biāo)題"]; //在鎖屏?xí)r顯示的動(dòng)作標(biāo)題(完整測(cè)標(biāo)題:"滑動(dòng)來(lái)" + alertAction)
[localNotification setApplicationIconBadgeNumber:1]; //設(shè)置提醒的軟件右上角的小紅點(diǎn)
[localNotification setSoundName:UILocalNotificationDefaultSoundName];//默認(rèn)聲音
//或者指定文件名localNotification.soundName = @"123.wav";
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; //調(diào)用通知
在本地消息調(diào)用之后,就會(huì)在通知欄顯示了,點(diǎn)擊通知欄的消息之后,會(huì)自動(dòng)打開(kāi)這個(gè)軟件,需要注意的是軟件不同的狀態(tài),點(diǎn)擊通知欄調(diào)用的函數(shù)也不同。
1、軟件如果是在后臺(tái)運(yùn)行,并沒(méi)有退出,調(diào)用的是AppDelegate的這個(gè)函數(shù)
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
2、軟件已經(jīng)主動(dòng)退出,或者后臺(tái)超過(guò)時(shí)間退出,點(diǎn)擊通知欄消息之后就只會(huì)調(diào)用這個(gè)函數(shù)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
3、所以不同的狀態(tài),調(diào)用的函數(shù)也不同,那么想獲取是哪個(gè)通知調(diào)用的函數(shù)方法也不相同了,如果是后臺(tái)運(yùn)行狀態(tài)下,想知道某個(gè)通知,可以通過(guò)不同的userInfo這樣實(shí)現(xiàn)
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
NSLog(@"Application did receive local notifications");
// 在這里寫(xiě)跳轉(zhuǎn)代碼
// 如果是應(yīng)用程序在前臺(tái),依然會(huì)收到通知,但是收到通知之后不應(yīng)該跳轉(zhuǎn)
if (application.applicationState == UIApplicationStateActive)
{
return;
}
if (application.applicationState == UIApplicationStateInactive) {
// 當(dāng)應(yīng)用在后臺(tái)收到本地通知時(shí)執(zhí)行的跳轉(zhuǎn)代碼
//可以通過(guò)設(shè)置通知時(shí)的userinfo過(guò)濾某條通知
if ([notification.userInfo[@"name"] isEqualToString:@"Damon"]) {
NSLog(@"damon");
}
//可以得到所有的通知
for (UILocalNotification *noti in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
NSLog(@"%@",noti.fireDate);
}
//通知之后可以取消對(duì)應(yīng)的通知
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
[self jump:1];
}
4、而如果app已經(jīng)退出,那么在啟動(dòng)函數(shù)里面獲取通知就需要通過(guò)launchOptions里面的UIApplicationLaunchOptionsLocalNotificationKey來(lái)實(shí)現(xiàn),比如這樣:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//當(dāng)應(yīng)用退出之后,點(diǎn)擊通知跳轉(zhuǎn)到應(yīng)用會(huì)走這個(gè)函數(shù),而不是didReceiveLocalNotification
UILocalNotification * local = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if ([local.userInfo[@"name"] isEqualToString:@"Damon"]) {
NSLog(@"damon");
[self jump:2];
}
return YES;
}
轉(zhuǎn)自:http://www.hudongdong.com/ios/348.html