NSNotification,又叫通知,屬于設計模式中的觀察者模式,在開發中很常見,相信大家都不陌生。關于NSNotification的用法以及它與delegate的區別,都是些老生常談的話題了,這里就不再說了。這篇文章主要想說幾個平時開發過程中,大家可能都沒有注意到的細節,我相信,當你理解了這些細節,你對NSNotification的認識會上升到另一個高度。
1、NSNotificationCenter是一種“同步”機制
先看看官方文檔的一段說明(Xcode->Window->Documentation And API Reference,搜索NSNotification):
A notification center delivers notifications to observers synchronously. In other words, when posting a notification, control does not return to the poster until all observers have received and processed the notification.
意思是,當notification center post了一個notification后,只有當所有observer接收了notification并且處理完了后程序才會返回,才會繼續執行post下面的代碼。
我們寫段代碼來驗證一下,也幫助加深理解。
- 注冊通知
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:kNotificationName object:nil];
}
- 處理通知
注意這里將線程休眠了5秒
- (void)handleNotification:(NSNotification *)notification {
NSString *msg = [NSString stringWithFormat:@"receive notification:%@", notification.object];
NSLog(@"%@", msg);
//休眠5s
sleep(5);
NSLog(@"notification handle finish...");
}
- 發送通知
- (IBAction)pushOnMainThread:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationName object:@"pushOnMainThread"];
NSLog(@"return...");
}
看下執行結果
可以看到,當我們postNotification后,Observer接收到notification并處理,確實是只有當Observer處理完成后(休眠了5s)程序才執行了postNotification后的代碼(打印return...),而且這期間主屏幕會卡主(因為同步執行,要等待程序返回)
由此可見:** 接收到通知后不易做耗時操作,否則可能會卡住主線程,導致屏幕卡頓。**
另外,提一下,可以通過Notification Queues實現異步發送通知(暫時沒去研究...??)
2、NSNotificationCenter可以在多線程里執行
還是先看一下官方文檔的說明:
In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself.
意思是,** notification在哪個線程里post,Observer就會在哪個線程里接收并處理,這個線程可能不是最初Observer被添加的線程。 **
在上面那段代碼里,我們是在主線程上添加的Observer(viewDidLoad里)
我們現在通過子線程post一個notification看看結果:
- handleNotification里打印當前線程
- (void)handleNotification:(NSNotification *)notification {
NSString *msg = [NSString stringWithFormat:@"receive notification:%@[%@]", notification.object, [NSThread currentThread]];
NSLog(@"%@", msg);
}
- 子線程中postNotification
- (IBAction)pushOnOtherThread:(id)sender {
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"post notification on other thread..%@",[NSThread currentThread]);
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationName object:@"pushOnOtherThread"];
});
}
執行結果如下:
可以看到,正如官方文檔里說明的那樣,當我們在其他線程里postNotification時,Observer確實是在那個線程里執行的。
所以,這里就會有個坑,當你要在Observer里更新UI的時候,如果notification是在其他線程里post的,那就可能會出現一些奇怪的問題了,比如主線程不響應,甚至是crash(注意crash不是必然的)。
- handleNotification里更新UI,異步postNotification
- (void)handleNotification:(NSNotification *)notification {
NSString *msg = [NSString stringWithFormat:@"receive notification:%@[%@]", notification.object, [NSThread currentThread]];
self.msgLabel.text = msg;
NSLog(@"%@", msg);
}
-
執行結果
程序沒有crash,msgLabel上的text確實正確顯示出來了,不過是延遲了幾秒鐘后才顯示出來的。同時在控制臺里會出現下面這段內容:
可以看到,接收到notification后又過了6秒,系統給出了一段說明,告知這個操作可能會導致奇怪的crash,但不是必定會crash,但是這種操作應該被避免。
結束語
說了一大堆,其實對平時開發可能幫助不大,因為大家已經習慣了在主線程里addObserver、postNotification,可能完全不會在意它可不可以在多線程里運行。Who care!
But! 如果你知道了這些,可能會對以后面試有幫助哦~~~??????