看一遍就會哦!
最近又干回了我的老本行 - iOS,感覺自己的邏輯思維比以前嚴密了許多,但是也發現有很多知識沒有掌握牢靠。在使用NSNotification時竟發現有些手生,趕緊抽時間整理一波,授人玫瑰,手有余香。
本文內容參考自官方API Reference
通知
Notification就是一個消息通知機制,類似廣播。觀察者向消息中心注冊感興趣的東西,當感興趣的東西發出這個消息的時候,觀察者就能接受到通知,然后去做相對應的事情。使用消息通知可以起到多個對象之間解耦的作用。蘋果封裝了常用的一些通知,比如窗口獲得焦點、網絡連接關閉等事件信息等。當然,我們也可以自定義個性化的通知。
通知中心,就是分發這些通知的地方,Cocoa框架中有兩種通知中心:
- NSNotificationCenter 單進程通知管理
- NSDistributedNotificationCenter 一臺機器中多個進程的通知管理
NSNotificationCenter
每個進程都包含一個默認的通知中心,這個通知中心是一個單例,通過[NSNotificationCenter defaultCenter]來獲取。
通知中心將通知分發給觀察者處理采用了同步機制,即當某一個通知被發送時,會一直阻塞在發送方法內,直到通知中心將該通知分發給注冊過的觀察者并且觀察者完成了相應的處理之后,發送者才能繼續執行其所在線程內的后續代碼。如果要使用異步機制發送通知,文章后面會講到“通知隊列”,即第二種通知中心。
開發以來,感覺通知常用的場景有兩個:
- 當前頁面給上一個頁面傳值。
- 當一個值發生改變時,相應的對象作出相應的操作。
創建通知
- (instancetype)initWithName:(NSNotificationName)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo;
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject;
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
這三個方法都能成功的創建一個通知,然而創建通知并不是必要的操作,因為在發送通知時,可以包含通知的各項參數。但是單獨講一下可以加深理解嘛。???
從上面三個方法可以看出,一個通知包含以下幾個參數:
- name:通知的名字,是通知能夠被接收到的關鍵因素。
- object:通知發送者希望發送給觀察者的一個對象,通常為通知發送者自己。
- userInfo:一個字典,是通知發送者傳遞給觀察者的參數。
發布通知
- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
第一個方法適用于發布已經通過NSNotification創建好的通知,其余兩個方法就在發布通知的時候,寫入了通知的具體參數。
注冊通知
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
在需要接收通知的位置注冊通知,注冊通知時需要設置:
- observer:觀察者,通常是self。
- selector:收到通知后,回調監聽器的這個方法,并且把通知對象當做參數傳入。
- name:通知的名稱,決定了觀察者所接收的通知。如果為nil,那么觀察者會接收到所有通知。
- object:通知的發布者。
注冊完通知之后就可以靜靜等待獵物的到來了。
移除通知
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;
移除通知是很重要的操作,因為通知中心是不會保留(retain)觀察者對象的,在通知中心注冊過的觀察者,必須在觀察者對象釋放前取消注冊。否則,當相應的通知再次出現時,通知中心仍然會向該觀察者發送消息。因為相應的觀察者對象已經被釋放了,所以可能會導致應用崩潰。
取消注冊的代碼一般寫在dealloc函數或者viewWillDisappear函數中。
舉個栗子
光說不練假把式。下面展示一個簡單的例子,在當前頁面dimiss的時候通過notification給上一個頁面傳值。
ViewController1
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//注冊通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyReceived:) name:@"notify" object:nil];
}
- (void)notifyReceived:(NSNotification *)content {
NSLog(@"-----接收到通知------");
NSLog(@"%@", content.userInfo[@"param"]);
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
//移除通知
[[NSNotificationCenter defaultCenter] removeObserve:self];
}
ViewController2
- (void)gotoNextVC {
//設置需要傳遞的參數
NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:@"我是一個參數",@"param", nil];
//創建通知
NSNotification *notification =[NSNotification notificationWithName:@"notify" object:nil userInfo:dict];
//通過通知中心發送通知
[[NSNotificationCenter defaultCenter] postNotification:notification];
[self dismissViewControllerAnimated:YES completion:nil];
}
NSDistributedNotificationCenter
分布式通知中心。這里就使用到了通知隊列(Notification queue),通知隊列通常以先進先出的順序管理通知,當一個通知到達隊首時,通知隊列就將這個通知發送給通知中心,通知中心將其派發給所有監聽它的觀察者們。
每一個線程都有一個默認的通知隊列,也是一個單例,通過[NSNotificationQueue defaultQueue]獲取。我們也可以自定義通知隊列,每個通知中心和線程可以有多個隊列。
這個就不細講了,如果下次有用到,會結合實際情況再進行總結的。
┌(???)?有用的話,動動