NSNotificationCenter/NSNotification 使用注意點全面解析

圖片來源NSHipster

為什么有NSNotification

  1. 可以實現(xiàn)跨層的傳遞,例如A頁面導航到B頁面,B頁面再導航到C頁面,這時候如果我們通過委托回調(diào)的模式讓A知道C的一些修改,那么實現(xiàn)起來就會很麻煩。
  2. 可以實現(xiàn)一對多,NSNotification的實現(xiàn)是一種觀察者模式,因此可以對通知實現(xiàn)廣播。

使用通知的要點

  1. ** 注冊多少次,他的執(zhí)行代碼就會執(zhí)行多少次 **
//1、注冊多個通知
for (int i =0; i<3; i++) {
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notifycationMehod:) name:@"testNotifycation" object:nil];
    }
//2、傳遞通知
 [[NSNotificationCenter defaultCenter]postNotificationName:@"testNotifycation" object:nil];

輸出結(jié)果

2016-12-01 17:06:23.868 NotifycationDemo[28703:10079806] receive notifycation object (null)
2016-12-01 17:06:23.868 NotifycationDemo[28703:10079806] receive notifycation object (null)
2016-12-01 17:06:23.869 NotifycationDemo[28703:10079806] receive notifycation object (null)
  1. 雖然注冊多次通知,但是移除一次通知,同一個對象通知就會全部移除**
//添加多個通知
    for (int i =0; i<3; i++) {
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notifycationMehod:) name:@"testNotifycation" object:nil];
    }
//移除通知
    [[NSNotificationCenter defaultCenter]removeObserver:self name:@"testNotifycation" object:nil];
    //發(fā)送通知
    [[NSNotificationCenter defaultCenter]postNotificationName:@"testNotifycation" object:nil];

這里不會有任何輸出

  1. add和Remove相關(guān)方法成對出現(xiàn)
    我們平時在使用通知的時候可能會在viewWillAppear方法里面add觀察者,viewWillDisappear里面remove,但是我們?nèi)绻況emove,那么如果我們導航到當前頁面再導航到另外一個頁面,然后再退回當前頁面,這時候我們會得到2個輸出結(jié)果。
- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    //注冊通知
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notifycationMehod:) name:@"testNotifycation" object:nil];
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    //沒有remove通知
}

輸出結(jié)果

2016-12-01 17:24:13.722 NotifycationDemo[28820:10087367] receive notifycation object (null)
2016-12-01 17:24:13.723 NotifycationDemo[28820:10087367] receive notifycation object (null)

4 . 移除一個name沒有add的通知,不會崩潰

[[NSNotificationCenter defaultCenter]removeObserver:self name:@"unknownName" object:nil];

5 . 一個對象添加了觀察者,但是沒有移除,程序不會崩潰,這是為啥

@implementation NotifyTestClass

- (void)registerMyNotifycation{
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notifycationMehod) name:@"testNotifycation" object:nil];
}

- (void)notifycationMehod{
    NSLog(@"NotifyTestClass receive notify");
}

- (void)dealloc{
    NSLog(@"NotifyTestClass dealloc");
}
@end

//局部變量 立刻釋放
 NotifyTestClass *nt = [[NotifyTestClass alloc]init];
 [nt registerMyNotifycation];
//發(fā)送通知
[[NSNotificationCenter defaultCenter]postNotificationName:@"testNotifycation" object:nil];

輸出結(jié)果

2016-12-01 19:29:15.039 NotifycationDemo[29035:10119206] NotifyTestClass dealloc

為了驗證這個問題我按這篇文章中提到的方法對NSNotificationCenter新建了一個category,然后重寫了remove方法;

//新建一個類別
@implementation NSNotificationCenter(NSNotificationCenterRemove)

- (void)removeObserver:(id)observer{
    NSLog(@"removeObserver = %@",observer);
}
- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject{
    NSLog(@"observer %@ name %@",observer,aName);
}
@end

然后我在輸出結(jié)果里面還是沒有看到在變量被dealloc之后有調(diào)用remove方法。因為按照這篇文章在最后說到通知中心對觀察者是unsafe_unretained引用,不是weak引用(weak和unsafe_unretained的區(qū)別,可以看我上一篇文章里面有提到),所以這個時候應該會崩潰的,因為相當于我對一個不存在的對象(野指針)發(fā)送了消息。這個問題困擾了我兩天沒搞明白,最后在一個群里問大家才發(fā)現(xiàn)問題的所在,蘋果官網(wǎng)文檔有說明,iOS 9.0之后NSNotificationCenter不會對一個dealloc的觀察者發(fā)送消息所以這樣就不會崩潰了。果真我換了一個8.1的手機測試,程序崩潰了,原來是做了優(yōu)化。

野指針異常
蘋果官網(wǎng)提示

6 . ViewController對象在銷毀的時候,系統(tǒng)會對他監(jiān)聽的通知進行清除

@implementation TwoViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notifycationMehod) name:@"testNotifycation" object:nil];
    // Do any additional setup after loading the view from its nib.
}
- (void)notifycationMehod{
    NSLog(@"TwoViewController receive notify");
}
- (void)dealloc{
    NSLog(@"TwoViewController dealloc");
}
@end

輸出結(jié)果

2016-12-02 16:36:42.175 NotifycationDemo[31359:10305477] TwoViewController dealloc
2016-12-02 16:36:42.176 NotifycationDemo[31359:10305477] removeObserver = <TwoViewController: 0x7fa42381d720>

7 . 處理方法是和post通知方法在同一線程同步執(zhí)行的
因此我們?nèi)绻邮芤恍┩ㄖ耈I的時候,我們需要回到主線程來處理。

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

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

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