關(guān)于NSNotification你可能不知道的東西

NSNotification,又叫通知,屬于設(shè)計(jì)模式中的觀察者模式,在開(kāi)發(fā)中很常見(jiàn),相信大家都不陌生。關(guān)于NSNotification的用法以及它與delegate的區(qū)別,都是些老生常談的話題了,這里就不再說(shuō)了。這篇文章主要想說(shuō)幾個(gè)平時(shí)開(kāi)發(fā)過(guò)程中,大家可能都沒(méi)有注意到的細(xì)節(jié),我相信,當(dāng)你理解了這些細(xì)節(jié),你對(duì)NSNotification的認(rèn)識(shí)會(huì)上升到另一個(gè)高度。

1、NSNotificationCenter是一種“同步”機(jī)制

先看看官方文檔的一段說(shuō)明(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.

意思是,當(dāng)notification center post了一個(gè)notification后,只有當(dāng)所有observer接收了notification并且處理完了后程序才會(huì)返回,才會(huì)繼續(xù)執(zhí)行post下面的代碼。
我們寫(xiě)段代碼來(lái)驗(yàn)證一下,也幫助加深理解。

  • 注冊(cè)通知
 - (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...");
}
  • 發(fā)送通知
 - (IBAction)pushOnMainThread:(id)sender {
    [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationName object:@"pushOnMainThread"];
    
    NSLog(@"return...");
}

看下執(zhí)行結(jié)果

可以看到,當(dāng)我們postNotification后,Observer接收到notification并處理,確實(shí)是只有當(dāng)Observer處理完成后(休眠了5s)程序才執(zhí)行了postNotification后的代碼(打印return...),而且這期間主屏幕會(huì)卡主(因?yàn)橥綀?zhí)行,要等待程序返回)

由此可見(jiàn):** 接收到通知后不易做耗時(shí)操作,否則可能會(huì)卡住主線程,導(dǎo)致屏幕卡頓。**
另外,提一下,可以通過(guò)Notification Queues實(shí)現(xiàn)異步發(fā)送通知(暫時(shí)沒(méi)去研究...??)

2、NSNotificationCenter可以在多線程里執(zhí)行

還是先看一下官方文檔的說(shuō)明:

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在哪個(gè)線程里post,Observer就會(huì)在哪個(gè)線程里接收并處理,這個(gè)線程可能不是最初Observer被添加的線程。 **
在上面那段代碼里,我們是在主線程上添加的Observer(viewDidLoad里)
我們現(xiàn)在通過(guò)子線程post一個(gè)notification看看結(jié)果:

  • handleNotification里打印當(dāng)前線程
 - (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"];
    });
}

執(zhí)行結(jié)果如下:


可以看到,正如官方文檔里說(shuō)明的那樣,當(dāng)我們?cè)谄渌€程里postNotification時(shí),Observer確實(shí)是在那個(gè)線程里執(zhí)行的。
所以,這里就會(huì)有個(gè)坑,當(dāng)你要在Observer里更新UI的時(shí)候,如果notification是在其他線程里post的,那就可能會(huì)出現(xiàn)一些奇怪的問(wèn)題了,比如主線程不響應(yīng),甚至是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);
}
  • 執(zhí)行結(jié)果
    程序沒(méi)有crash,msgLabel上的text確實(shí)正確顯示出來(lái)了,不過(guò)是延遲了幾秒鐘后才顯示出來(lái)的。同時(shí)在控制臺(tái)里會(huì)出現(xiàn)下面這段內(nèi)容:


可以看到,接收到notification后又過(guò)了6秒,系統(tǒng)給出了一段說(shuō)明,告知這個(gè)操作可能會(huì)導(dǎo)致奇怪的crash,但不是必定會(huì)crash,但是這種操作應(yīng)該被避免。

結(jié)束語(yǔ)

說(shuō)了一大堆,其實(shí)對(duì)平時(shí)開(kāi)發(fā)可能幫助不大,因?yàn)榇蠹乙呀?jīng)習(xí)慣了在主線程里addObserver、postNotification,可能完全不會(huì)在意它可不可以在多線程里運(yùn)行。Who care!
But! 如果你知道了這些,可能會(huì)對(duì)以后面試有幫助哦~~~??????

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容