標籤:ase ram 單例設計 color 使用 reg with mod files
原文地址 : http://www.jianshu.com/p/1208724e1915
iOS 提供了一種 “同步的” 訊息通知機制NSNotificationCenter,觀察者只要向訊息中心註冊, 即可接受其他對象發送來的訊息,訊息寄件者和訊息接受者兩者可以互相一無所知,完全解耦。
訊息機制常常用於在向伺服器端請求資料或者提交資料的情境,在和伺服器端成功互動後,需要處理伺服器端返回的資料,或發送響應訊息等,就需要用到訊息機制
一、通知相關的類
NSNotification 這個類可以理解為一個訊息對象,其中包含三個屬性
@property (readonly, copy) NSNotificationName name;//訊息對象的唯一標識,用於辨別訊息對象。
@property (nullable, readonly, retain) id object;//
@property (nullable, readonly, copy) NSDictionary *userInfo;//用來傳遞訊息
NSNotification的初始化方法:
- (instancetype)initWithName:(NSNotificationName)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo NS_AVAILABLE(10_6, 4_0) NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject;
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
- (instancetype)init //不能調用 /NS_UNAVAILABLE/; / do not invoke; not a valid initializer for this class /
注意:官方文檔有明確的說明,不可以使用init進行初始化
NSNotificationCenter這個類是通知中樞,用單例設計,每個應用程式都會有一個預設的通知中樞,用於調度通知的發送和接受。
添加一個觀察者,可以為它指定一個方法,名字和對象。接收到通知時,執行方法。
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;
參數解析:Observer:(誰來接受通知訊息);selector(方法選擇,執行哪個方法); name:(通知的名稱,也可以說是通知訊息的標識,按照這個來區分是否接受通知);object:(接受誰的通知(進行篩選),用這個參設定,nil為接受所有檔案 發送的通知)。
發送通知訊息的方法
- (void)postNotification:(NSNotification )notification;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary )aUserInfo;
參數解析:Name:(通知標識,與註冊通知是的標識對應);object:(發送方);userInfo:(重點說一下,這是一個字典類型的對象,可以把需要傳遞 的值放進這個字典裡)
移除通知的方法
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;
注意:1.如果發送的通知指定了object對象,那麼觀察者接收的通知設定的object對象與其一樣,才會接收通知。但是接收通知如果將這個參數設定為nil則會接收一切通知。
2.觀察者的SEL函數指標可以有一個參數,參數就是發送的訊息對象本身,可以通過這個參數取到訊息對象的usetInfo,實現傳值。
二、通知的使用流程
要想完成一個通知,主要有分三個執行步驟,而且是按順序來的
順序很重要,順序很重要,順序很重要,重要的事情說三遍
1.要保證註冊通知在發送訊息之前
- 首先,在需要接收通知的地方註冊觀察者,比如
//擷取通知中樞單例對象
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
//添加當前類對象為一個觀察者,name和object設定為nil,表示接收一切通知
[center addObserver:self selector:@selector(notice:) name:@"aha" object:nil];
- 然後,在我們需要時發送通知訊息
//建立訊息對象
NSNotification *notification = [[NSNotification alloc]initWithName:@"aha" object:@"hah" userInfo:@{@"我是訊息":@"hello"}];
//使用通知中樞發送通知
[[NSNotificationCenter defaultCenter]postNotification:notification];
- 最後移除通知
//移除通知
[[NSNotificationCenter defaultCenter]removeObserver:self name:@"aha" object:nil];
三、通知知識注意事項及拓展
通知一般用在反向傳值,如果要實現正向傳值則必須保證:註冊通知在發送通知之前實現
可以參考:Mazy_ma的部落格:iOS-通知正向傳值問題
多個監聽者監聽同一個訊息時:
監聽同一條通知的多個觀察者,在通知到達時,它們執行回調的順序是不確定的,所以我們不能去假設操作的執行會按照添加觀察者的順序來執行
關於註冊監聽者,還有一個需要注意的問題是,每次調用addObserver時,都會在通知中樞重新註冊一次,即使是同一對象監聽同一個訊息,而不是去覆蓋原來的監聽。這樣,當通知中樞轉寄某一訊息時,如果同一對象多次註冊了這個通知的觀察者,則會收到多個通知。
預設的通知是同步的:
代碼如下:
-(void)viewDidLoad { [super viewDidLoad]; //註冊通知觀察者 [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(comeTrueNotification:) name:kNotificationName object:@"wow"]; UIButton *sendNoticeBtn = [UIButton buttonWithType:UIButtonTypeSystem]; [sendNoticeBtn setFrame:CGRectMake(100, 100, 100, 100)]; [sendNoticeBtn setBackgroundColor:[UIColor cyanColor]]; [sendNoticeBtn setTitle:@"sendBtn" forState:UIControlStateNormal]; [self.view addSubview:sendNoticeBtn]; [sendNoticeBtn addTarget:self action:@selector(sendNoticeBtnDown) forControlEvents:UIControlEventTouchUpInside]; NSLog(@"%d,%@,viewDidLoad",__LINE__,[NSThread currentThread]);
}
-(void)comeTrueNotification:(NSNotification *)notification {
NSString *message = notification.object; //執行訊息方法 NSLog(@"%d,%@,%@",__LINE__,[NSThread currentThread],message); sleep(5); NSLog(@"%d,%@,comeTrueNotification",__LINE__,[NSThread mainThread]);
}
-(void)sendNoticeBtnDown {
//發送訊息 [[NSNotificationCenter defaultCenter]postNotificationName:kNotificationName object:@"wow"]; NSLog(@"%d,%@,sendNoticeBtnDown",__LINE__,[NSThread currentThread]);
}
運行結果:
控制台展示.png
可以參考好文:NSNotificationCenter的同步和非同步
通知非同步處理方法:(參考:NSNotificationCenter的同步和非同步)
- 通知非同步方法呼叫一:
讓通知事件處理方法在子線程中執行:(例如:)dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(5);
});
- 通知非同步方法呼叫二:
您可以通過NSNotificationQueue的enqueueNotification:postingStyle:和enqueueNotification:postingStyle:coalesceMask:forModes:方法將通告放入隊列,實現非同步發送,在把通告放入隊列之後,這些方法會立即將控制權返回給調用對象。
我們修改sendNoticeBtnDown事件如下:
//發送訊息
NSNotification *notification = [NSNotification notificationWithName:kNotificationName object:@"wow"];
[[NSNotificationQueue defaultQueue]enqueueNotification:notification postingStyle:NSPostASAP];
// [[NSNotificationCenter defaultCenter]postNotificationName:kNotificationName object:@"wow"];
通過通知隊列來管理通知,不會再造成阻塞
關於通知的移除
雖然在 IOS 用上 ARC 後,不顯示移除 NSNotification Observer 也不會出錯,但是這是一個很不好的習慣,不利於效能和記憶體。
登出觀察者有2個方法:
a. 最優的方法,在 UIViewController.m 中:
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
b. 單個移除:
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"Notification_GetUserProfileSuccess" object:nil];
注意:
removeObserver:是刪除通知中樞儲存的調度表一個觀察者的所有入口,而removeObserver:name:object:是刪除匹配了通知中樞儲存的調度表中觀察者的一個入口。
這個比較簡單,直接調用該方法就行。例如:
[[NSNotificationCenter defaultCenter] removeObserver:observer name:nil object:self];
注意參數notificationObserver為要刪除的觀察者,一定不能置為nil。
iOS 通知中樞