NSNotification

啥時(shí)候用:

沒有明顯層級(jí)關(guān)系的時(shí)候用.

例如在推送通知的時(shí)候,因?yàn)槲覀儾⒉恢涝谑裁磿r(shí)間點(diǎn)會(huì)觸發(fā)推送,也不知道觸發(fā)時(shí)當(dāng)前應(yīng)用出于哪一個(gè)頁(yè)面,所以使用通知.相反,如果此時(shí)通過navgation controller遍歷節(jié)點(diǎn),查詢相關(guān)節(jié)點(diǎn),做出相應(yīng)操作就不太好了.

在有明顯層級(jí)關(guān)系的時(shí)候,例如A頁(yè)面需要選擇城市,點(diǎn)擊按鈕后彈出B城市篩選頁(yè)面,選擇城市后B頁(yè)面消失,A頁(yè)面做出相應(yīng)操作.這種情況就不適合.使用Delegate/KVO/Block均好于Notification

取消地點(diǎn):

在UIViewController中,如果可以不再dealloc方法里面取消,盡量不要在.

如果可以的話,盡量在Appear(will/did)的時(shí)候進(jìn)行Add/Remove Observer.當(dāng)然要配對(duì)好.

dealloc是個(gè)挺危險(xiǎn)的方法.相信每個(gè)人都有各式各樣的問題導(dǎo)致內(nèi)存沒有釋放.盡管這可以通過查找內(nèi)存泄露來(lái)解決.

但是泄露內(nèi)存隨著iPhone硬件的提升,很多時(shí)候不并不會(huì)造成嚴(yán)重的后果.但是重復(fù)的通知發(fā)送,可能會(huì)導(dǎo)致嚴(yán)重而又詭異的bug.

盡量在安全的地方Remove.當(dāng)然,這并不代表我們可以忽略對(duì)內(nèi)存的管理.不是這個(gè)意思...

安全刪除:

在一個(gè)Object注冊(cè)了很多個(gè)通知的情況下,有人喜歡用[[NSNotificationCenter defaultCenter] removeObserver:self]來(lái)一次性刪除.

但,真的好么?
不好.

因?yàn)樗鼰o(wú)法刪除帶有block的Notifcation.

盡量配對(duì)的好,有添也有刪.

Block的Notification:

指的是這個(gè)方法:

- (id <NSObject>)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block

使用weak/strong大法.不然在調(diào)用self等的時(shí)候,會(huì)造成引用循環(huán).

似乎印象中,系統(tǒng)的block不會(huì)造成引用循環(huán),比如UIView的animation.別經(jīng)驗(yàn)主義,為了保證安全,我們甚至可以在所有的block中均使用weak/strong大法.

它會(huì)返回一個(gè)observer對(duì)象,我們需要記著刪除他.當(dāng)然,在這之前我們需要根據(jù)業(yè)務(wù)邏輯來(lái)決定持有該對(duì)象多久.

Notification Once:

詳見:Nofication Once---by孫源

在AFNetworking中也能看到此代碼,UIAlertView+AFNetworking.h中的方法:

#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
+ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task
                                         delegate:(id)delegate
                                cancelButtonTitle:(NSString *)cancelButtonTitle
                                otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION
{
    NSMutableArray *mutableOtherTitles = [NSMutableArray array];
    va_list otherButtonTitleList;
    va_start(otherButtonTitleList, otherButtonTitles);
    {
        for (NSString *otherButtonTitle = otherButtonTitles; otherButtonTitle != nil; otherButtonTitle = va_arg(otherButtonTitleList, NSString *)) {
            [mutableOtherTitles addObject:otherButtonTitle];
        }
    }
    va_end(otherButtonTitleList);

    __block __weak id<NSObject> observer = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingTaskDidCompleteNotification object:task queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) {
        NSError *error = notification.userInfo[AFNetworkingTaskDidCompleteErrorKey];
        if (error) {
            NSString *title, *message;
            AFGetAlertViewTitleAndMessageFromError(error, &title, &message);

            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:nil delegate:delegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil, nil];
            for (NSString *otherButtonTitle in mutableOtherTitles) {
                [alertView addButtonWithTitle:otherButtonTitle];
            }
            [alertView setTitle:title];
            [alertView setMessage:message];
            [alertView show];
        }

        [[NSNotificationCenter defaultCenter] removeObserver:observer];
    }];
}
#endif

該技巧可以讓我們只注冊(cè)一次通知,使用完畢后,即被刪除.

有兩點(diǎn)需要注意.

  1. block的的notification的返回值,前面是否帶__block關(guān)鍵字是完全不一樣的,決定block對(duì)于返回值的捕獲.

  2. 除了帶上__block,盡量帶上__weak或者在block中手動(dòng)將返回值置為nil

利用ARC更好的使用Notication

Notification最常見的問題就是忘記刪除.當(dāng)出現(xiàn)此類問題的時(shí)候,非常不好排查.而引發(fā)的問題可能是巨大的,并且詭異難以debug.

所以結(jié)合ARC的特性,可以更優(yōu)雅的使用Notification.

思路是我們通過一個(gè)對(duì)象來(lái)管理通知.在注冊(cè)通知的時(shí)候,通過一定的數(shù)據(jù)結(jié)構(gòu)作好記錄.在對(duì)象dealloc的時(shí)候,刪除記錄的通知對(duì)象.

因?yàn)锳RC,所以我們不需要手動(dòng)顯示的釋放該對(duì)象.該對(duì)象釋放的時(shí)候,也就相應(yīng)的刪除了通知.

當(dāng)然,github上有更多更好的輪子.在實(shí)際生產(chǎn)中,或許我們可以使用已經(jīng)造好的輪子.

線程:

帶有block的Notification,有一個(gè)參數(shù)是queue.意思是指定執(zhí)行block的線程.如果沒有指定,則在post對(duì)象的線程中執(zhí)行.

所以,如果沒有指定線程的話,那么這個(gè)block可能會(huì)在任何一個(gè)線程中執(zhí)行,這完全取決于誰(shuí)在post.

所以,如果是ui相關(guān)操作的話,最好我們指定為主線程.

另外,有A,B 2個(gè)對(duì)象,分別處于2個(gè)線程中.A post了一個(gè)notification,在notification中將會(huì)使用C對(duì)象執(zhí)行一系列方法.而B對(duì)象恰恰又釋放了C

對(duì)象.那么此時(shí)會(huì)不會(huì)出現(xiàn)問題.

答案是會(huì)的.

怎么辦呢?

盡量使用block的Notification,畢竟block會(huì)捕獲相關(guān)變量.

更多的線程請(qǐng)參考Notification與多線程---by南峰子

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,653評(píng)論 30 472
  • 1.OC里用到集合類是什么? 基本類型為:NSArray,NSSet以及NSDictionary 可變類型為:NS...
    輕皺眉頭淺憂思閱讀 1,483評(píng)論 0 3
  • 簡(jiǎn)述 NSNotification 是iOS中一個(gè)消息通知類,存儲(chǔ)消息的一些信息;NSNotificationCe...
    小白進(jìn)城閱讀 1,187評(píng)論 1 5
  • KVC KVC (key-value observing) 是基于 NSKeyValueCoding 的一個(gè)非正式...
    漂泊海上的大土豆閱讀 462評(píng)論 0 4
  • 早上來(lái)圖書館占個(gè)坐,是大部分學(xué)生的日常,要是遇到期末考試,圖書館坐無(wú)虛席。我有自己看書的工作室,里面配有電腦...
    爾古閱讀 331評(píng)論 2 0

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