關于NSNotification你可能不知道的東西

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! 如果你知道了這些,可能會對以后面試有幫助哦~~~??????

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容