- **
通知機(jī)制(消息機(jī)制)
是一個(gè)應(yīng)用程序級(jí)別
的操作UIApplication -
通知中心
實(shí)際上是iOS程序內(nèi)部之間的一種消息廣播機(jī)制
茉贡,主要為了解決應(yīng)用程序
內(nèi)部不同對(duì)象
之間解耦
而設(shè)計(jì)。它是基于觀察者模式
設(shè)計(jì)的潮酒,不能跨應(yīng)用程序進(jìn)程通信
坟冲,當(dāng)通知中心
接收到消息之后會(huì)根據(jù)內(nèi)部的消息轉(zhuǎn)發(fā)表
磨镶,將消息發(fā)送給訂閱者
。
通知機(jī)制 與 NSNotification 區(qū)別
- NSNotification是抽象的健提,不可見(jiàn)的
- 推送通知是可見(jiàn)的(能用肉眼看到)
- 對(duì)于很多初學(xué)者往往會(huì)把iOS中的本地通知琳猫、推送通知和iOS通知中心的概念弄混。其實(shí)二者之間并沒(méi)有任何關(guān)系私痹,事實(shí)上它們都不屬于一個(gè)框架脐嫂,前者屬于UIKit框架统刮,后者屬于Foundation框架。
下面是一個(gè)簡(jiǎn)單的通知中心流程示意圖:
了解通知中心需要熟悉NSNotificationCenter和NSNotification兩個(gè)類(lèi):
- NSNotificationCenter:是通知系統(tǒng)的中心账千,用于注冊(cè)和發(fā)送通知侥蒙,下表列出常用的方法
NSNotification:代表通知內(nèi)容的載體,主要有三個(gè)屬性:name代表通知名稱(chēng)匀奏,object代表通知的發(fā)送者鞭衩,userInfo代表通知的附加信息。
很多東西都是通過(guò)通知中心來(lái)進(jìn)行應(yīng)用中各個(gè)組件通信娃善。例如說(shuō)道應(yīng)用程序生命周期問(wèn)題论衍,當(dāng)應(yīng)用程序啟動(dòng)后、進(jìn)入后臺(tái)聚磺、進(jìn)入前臺(tái)坯台、獲得焦點(diǎn)、失去焦點(diǎn)瘫寝,窗口大小改變蜒蕾、隱藏等都會(huì)發(fā)送通知。這個(gè)通知可以通過(guò)前面NSNotificationCenter進(jìn)行訂閱即可接收對(duì)應(yīng)的消息焕阿,下面的示例演示如何添加監(jiān)聽(tīng)獲得UIApplication的進(jìn)入后臺(tái)和獲得焦點(diǎn)的通知:
//
// LTYViewController.m
// NotificationCenter
//
#import "LTYViewController.h"
@interface LTYViewController ()
@end
@implementation LTYViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self addObserverToNotificationCenter];
}
#pragma mark 添加監(jiān)聽(tīng)
-(void)addObserverToNotificationCenter{
/*添加應(yīng)用程序進(jìn)入后臺(tái)監(jiān)聽(tīng)
* observer:監(jiān)聽(tīng)者
* selector:監(jiān)聽(tīng)方法(監(jiān)聽(tīng)者監(jiān)聽(tīng)到通知后執(zhí)行的方法)
* name:監(jiān)聽(tīng)的通知名稱(chēng)(下面的UIApplicationDidEnterBackgroundNotification是一個(gè)常量)
* object:通知的發(fā)送者(如果指定nil則監(jiān)聽(tīng)任何對(duì)象發(fā)送的通知)
*/
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication]];
/* 添加應(yīng)用程序獲得焦點(diǎn)的通知監(jiān)聽(tīng)
* name:監(jiān)聽(tīng)的通知名稱(chēng)
* object:通知的發(fā)送者(如果指定nil則監(jiān)聽(tīng)任何對(duì)象發(fā)送的通知)
* queue:操作隊(duì)列滥搭,如果制定非主隊(duì)線(xiàn)程隊(duì)列則可以異步執(zhí)行block
* block:監(jiān)聽(tīng)到通知后執(zhí)行的操作
*/
NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:[UIApplication sharedApplication] queue:operationQueue usingBlock:^(NSNotification *note) {
NSLog(@"Application become active.");
}];
}
#pragma mark 應(yīng)用程序啟動(dòng)監(jiān)聽(tīng)方法
- (void)applicationEnterBackground{
NSLog(@"Application enter background.");
}
@end
- 當(dāng)然很多時(shí)候使用通知中心是為了添加自定義通知,并獲得自定義通知消息捣鲸。比如多視圖之間參數(shù)傳遞,其實(shí)利用自定義通知也可以進(jìn)行參數(shù)傳遞闽坡。通常一個(gè)應(yīng)用登錄后會(huì)顯示用戶(hù)信息栽惶,而登錄信息可以通過(guò)登錄界面獲取。下面就以這樣一種場(chǎng)景為例疾嗅,在主界面中添加監(jiān)聽(tīng)外厂,在登錄界面發(fā)送通知,一旦登錄成功將向通知中心發(fā)送成功登錄的通知代承,此時(shí)主界面中由于已經(jīng)添加通知監(jiān)聽(tīng)所以會(huì)收到通知并更新UI界面汁蝶。
主界面LTYViewController.m
//
// LTYViewController.m
// NotificationCenter
//
#import "LTYViewController.H"
#import "LTYoginViewController.h"
#define UPDATE_LGOGIN_INFO_NOTIFICATION @"updateLoginInfo"
@interface LTYViewController () {
UILabel *_lbLoginInfo;
UIButton *_btnLogin;
}
@end
@implementation LTYViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
}
- (void)setupUI{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 100,320 ,30)];
label.textAlignment = NSTextAlignmentCenter;
label.textColor=[UIColor colorWithRed:23/255.0 green:180/255.0 blue:237/255.0 alpha:1];
_lbLoginInfo = label;
[self.view addSubview:label];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame=CGRectMake(60, 200, 200, 25);
[button setTitle:@"登錄" forState:UIControlStateNormal];
[button addTarget:self action:@selector(loginOut) forControlEvents:UIControlEventTouchUpInside];
_btnLogin = button;
[self.view addSubview:button];
}
- (void)loginOut{
//添加監(jiān)聽(tīng)
[self addObserverToNotification];
LTYLoginViewController *loginController=[[LTYLoginViewController alloc] init];
[self presentViewController:loginController animated:YES completion:nil];
}
/**
* 添加監(jiān)聽(tīng)
*/
- (void)addObserverToNotification{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateLoginInfo:) name:UPDATE_LGOGIN_INFO_NOTIFICATION object:nil];
}
/**
* 更新登錄信息,注意在這里可以獲得通知對(duì)象并且讀取附加信息
*/
- (void)updateLoginInfo:(NSNotification *)notification{
NSDictionary *userInfo=notification.userInfo;
_lbLoginInfo.text=userInfo[@"loginInfo"];
_btnLogin.titleLabel.text=@"注銷(xiāo)";
}
- (void)dealloc{
//移除監(jiān)聽(tīng)
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
登錄界面LTYLoginViewController.m
//
// LTYLoginViewController.m
// NotificationCenter
//
#import "LTYLoginViewController.H"
#define UPDATE_LGOGIN_INFO_NOTIFICATION @"updateLoginInfo"
@interface LTYLoginViewController (){
UITextField *_txtUserName;
UITextField *_txtPassword;
}
@end
@implementation LTYLoginViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
}
/**
* UI布局
*/
- (void)setupUI{
//用戶(hù)名
UILabel *lbUserName=[[UILabel alloc]initWithFrame:CGRectMake(50, 150, 100, 30)];
lbUserName.text=@"用戶(hù)名:";
[self.view addSubview:lbUserName];
_txtUserName=[[UITextField alloc]initWithFrame:CGRectMake(120, 150, 150, 30)];
_txtUserName.borderStyle=UITextBorderStyleRoundedRect;
[self.view addSubview:_txtUserName];
//密碼
UILabel *lbPassword=[[UILabel alloc]initWithFrame:CGRectMake(50, 200, 100, 30)];
lbPassword.text=@"密碼:";
[self.view addSubview:lbPassword];
_txtPassword=[[UITextField alloc]initWithFrame:CGRectMake(120, 200, 150, 30)];
_txtPassword.secureTextEntry=YES;
_txtPassword.borderStyle=UITextBorderStyleRoundedRect;
[self.view addSubview:_txtPassword];
//登錄按鈕
UIButton *btnLogin=[UIButton buttonWithType:UIButtonTypeSystem];
btnLogin.frame=CGRectMake(70, 270, 80, 30);
[btnLogin setTitle:@"登錄" forState:UIControlStateNormal];
[self.view addSubview:btnLogin];
[btnLogin addTarget:self action:@selector(login) forControlEvents:UIControlEventTouchUpInside];
//取消登錄按鈕
UIButton *btnCancel=[UIButton buttonWithType:UIButtonTypeSystem];
btnCancel.frame=CGRectMake(170, 270, 80, 30);
[btnCancel setTitle:@"取消" forState:UIControlStateNormal];
[self.view addSubview:btnCancel];
[btnCancel addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark 登錄操作
-(void)login{
if ([_txtUserName.text isEqualToString:@"ayuan"] && [_txtPassword.text isEqualToString:@"123"] ) {
//發(fā)送通知
[self postNotification];
[self dismissViewControllerAnimated:YES completion:nil];
}else{
//登錄失敗彈出提示信息
UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:@"系統(tǒng)信息" message:@"用戶(hù)名或密碼錯(cuò)誤,請(qǐng)重新輸入论悴!" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];
[alertView show];
}
}
#pragma mark 點(diǎn)擊取消
-(void)cancel{
[self dismissViewControllerAnimated:YES completion:nil];
}
/**
* 添加通知掖棉,注意這里設(shè)置了附加信息
*/
-(void)postNotification{
NSDictionary *userInfo=@{@"loginInfo":[NSString stringWithFormat:@"Hello,%@!",_txtUserName.text]};
NSLog(@"%@",userInfo);
NSNotification *notification=[NSNotification notificationWithName:UPDATE_LGOGIN_INFO_NOTIFICATION object:self userInfo:userInfo];
[[NSNotificationCenter defaultCenter] postNotification:notification];
//也可直接采用下面的方法
// [[NSNotificationCenter defaultCenter] postNotificationName:UPDATE_LGOGIN_INFO_NOTIFICATION object:self userInfo:userInfo];
}
@end
- 通知中心是一種低耦合設(shè)計(jì),和代理模式有異曲同工之妙膀估。相對(duì)于后者而言幔亥,通知中心可以將一個(gè)通知發(fā)送給多個(gè)監(jiān)聽(tīng)者,而每個(gè)對(duì)象的代理卻只能有一個(gè)察纯。當(dāng)然代理也有其優(yōu)點(diǎn)帕棉,例如使用代理代碼分布結(jié)構(gòu)更加清晰针肥,它不像通知一樣隨處都可以添加訂閱等,實(shí)際使用過(guò)程中需要根據(jù)實(shí)際情況而定香伴。