iOS 通知基礎(chǔ)介紹

簡述

NSNotification 是iOS中一個消息通知類抬旺,存儲消息的一些信息崭倘;
NSNotificationCenter 是一個通知中心问芬,采用單例設(shè)計模式悦析,用來發(fā)布、接收等消息操作的類此衅。

NSNotification介紹

首先來看下强戴,NSNotification類可以存儲哪些消息信息亭螟。

// 消息的名稱,操作對應(yīng)的消息的依據(jù)骑歹,只讀
@property (readonly, copy) NSNotificationName name;
// 消息對象预烙,只讀
@property (nullable, readonly, retain) id object;
// 存儲消息信息的字典,只讀
@property (nullable, readonly, copy) NSDictionary *userInfo;

從上面可以看出道媚,NSNotification 類使用一個 userInfo 字典來存儲消息信息的扁掸,并使用一個name字符串來標(biāo)識消息。

如何創(chuàng)建一個消息呢最域?

實例方法:

// 參數(shù)分別為:消息名稱谴分、對象、消息字典
- (instancetype)initWithName:(NSNotificationName)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo;

系統(tǒng)后來又使用分類新增了兩種快捷獲取消息的類方法

+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject;
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

使用上面兩種類方法可以省去我們手動分配空間的操作镀脂,可以根據(jù)業(yè)務(wù)需求選擇其一即可牺蹄;
注:系統(tǒng)明確指出不要調(diào)用 init 方法來初始化一個消息對象,而且NSNotification的屬性name薄翅、object沙兰、userInfo都被設(shè)計為只讀的,可能是出于消息安全考慮吧

NSNotificationCenter介紹

假如我們使用NSNotification類創(chuàng)建了一條消息翘魄,接下來如何發(fā)送該消息呢鼎天?這時就需要具有發(fā)布通知功能的類NSNotificationCenter(即通知中心)了。

注:在發(fā)布消息前暑竟,我們首先需要向通知中心一個注冊一個消息監(jiān)聽者來接收我們將要發(fā)布的消息

首先獲取通知中心

// [NSNotificationCenter defaultCenter]
@property (class, readonly, strong) NSNotificationCenter *defaultCenter;

向該通知中心注冊一個監(jiān)聽者斋射。

// 最常用的注冊通知方法
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;
// 注冊通知的block形式
- (id <NSObject>)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block;

如果我們創(chuàng)建好了一個通知 notification,就可以使用下面的方法發(fā)送通知光羞。

- (void)postNotification:(NSNotification *)notification;

如果你并沒有一個消息對象绩鸣,你也可以在發(fā)布消息時直接創(chuàng)建。

// 只傳遞消息
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
// 數(shù)據(jù)字典一并發(fā)布
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

注:NSNotificationCenter 實現(xiàn)的過程實質(zhì)是:某個對象向NSNotificationCenter注冊需要接收某種消息纱兑,NSNotificationCenter便保存了這個對象的內(nèi)存地址呀闻,當(dāng)發(fā)布消息時,NSNotificationCenter就向該內(nèi)存地址發(fā)送消息潜慎;那么假如這個對象內(nèi)存已經(jīng)被釋放捡多,即成為了僵尸對象,指向該地址的指針也就成了野指針铐炫,這時候當(dāng)NSNotificationCenter將消息發(fā)送給該地址時垒手,就會出現(xiàn)crash情況。這是在某個類使用通知的情況倒信,但是在控制器中卻不會crash科贬,原因是控制器在調(diào)用dealloc時,會默默的幫我們移除通知。

但是榜掌,為了規(guī)范优妙,一個addObserver就應(yīng)該對應(yīng)一個removeObserver。

移除觀察者

// 移除observer上多有的注冊
- (void)removeObserver:(id)observer;
// 移除指定的消息類型
- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;

使用通知

使用通知比較簡單一共分三步

步驟一:注冊通知憎账,新增消息類型以及接收者
步驟二:發(fā)送通知
步驟三:移除通知套硼,即移除消息接收者

過程可以理解為:當(dāng)某些個對象需要某種類型的消息時,便向NSNotificationCenter通知中心注冊胞皱,NSNotificationCenter便將該消息和該對象綁定(保存該對象的內(nèi)存地址)邪意,合適時機(jī),NSNotificationCenter便發(fā)布消息反砌,注冊對象根據(jù)消息消息類型(name)選擇性接收(name相同才接收)雾鬼,當(dāng)注冊對象內(nèi)存被釋放時,需要手動移除NSNotificationCenter中對應(yīng)的注冊對象于颖。

應(yīng)用情景:頁面跳轉(zhuǎn)時呆贿,我們給下一個頁面發(fā)送一條消息

當(dāng)前頁面

- (void)viewDidLoad {
    [super viewDidLoad];
    // 對象參數(shù)
    UIButton *btn = [UIButton new];
    [btn setTitle:@"btn title" forState:UIControlStateNormal];
    // 信息字典
    NSDictionary *dic = @{@"name":@"lolita0164"};
    // 創(chuàng)建一則消息
    NSNotification *notification = [[NSNotification alloc] initWithName:@"lolita0164" object:btn userInfo:dic];
    
    // 模擬業(yè)務(wù)嚷兔,延遲5秒發(fā)布消息
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 發(fā)布消息
        [[NSNotificationCenter defaultCenter] postNotification:notification];
    });
    
}

下一個頁面 NextPageViewController.h

- (void)viewDidLoad {
    [super viewDidLoad];
    // 注冊消息
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(noti:) name:@"lolita0164" object:nil];
}

// 消息處理
-(void)noti:(NSNotification *)noti{
    NSLog(@"%@接收到的消息:%@",[self class],noti.userInfo);
    UIButton *btn = noti.object;
    NSLog(@"%@接收到的消息:%@",[self class],btn.titleLabel.text);
}

// 對象釋放時森渐,移除該注冊對象
-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"lolita0164" object:nil];
    NSLog(@"%@釋放了",[self class]);
}

運(yùn)行結(jié)果

通知例子

消息線程的選擇

NSNotificationCenter消息的接受線程是基于發(fā)送消息的線程的,因此冒晰,有時候你發(fā)送的消息有時候可能不在主線程同衣,而大家都知道操作UI必須在主線程,所以壶运,在你收到消息通知的時候耐齐,注意選擇你要執(zhí)行的線程。

比如對于需要更新UI的通知蒋情,我們在主線程中更新UI

發(fā)送的消息非主線程中

dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(defaultQueue, ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:@"UIUpdate" object:nil];
    });

- (void)UIUpdate{
    if ([[NSThread currentThread] isMainThread]) {
        NSLog(@"main");
    } else {
        NSLog(@"not main");
    }
    // 主線程中更新UI
    dispatch_async(dispatch_get_main_queue(), ^{
        //更新UI操作
    });
}

輸出結(jié)果:

非主線程中發(fā)送消息

來說下注冊通知的block形式的使用埠况,該方法讓我們可以直接指定什么線程去完成消息處理。

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

示例

// 注冊并接收處理消息
self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"lolita0164" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
    NSLog(@"%@接收到的消息:%@",[self class],note.userInfo);
    UIButton *btn = note.object;
    NSLog(@"%@接收到的消息:%@",[self class],btn.titleLabel.text);
}];

如果參數(shù)隊列不指定棵癣,為nil辕翰,則表示和發(fā)送消息的線程一致。

注銷操作

[[NSNotificationCenter defaultCenter] removeObserver:self.observer];
self.observer = nil; // 將該對象一并注銷

注意事項

1狈谊、注冊通知必須在發(fā)送通知之前

2喜命、注冊和發(fā)布消息的類型name要一致

3、消息接收對象必須存在河劝,若不存在,則需要手動移除該消息接收對象

4、viewDidLoad里注冊赞哗,dealloc中移除融柬;或者viewWillAppear:里注冊,viewWillDisappear:移除

5务甥、移除通知最好指定消息類型name牡辽,否則可能移除掉其他對其他消息的監(jiān)聽

擴(kuò)展

1贪染、和KVO對比?

  • 兩者都是屬于觀察者設(shè)計模式催享,但是通知更靈活杭隙,適用更廣,比起KVO因妙,通知可以用來監(jiān)聽狀態(tài)的變化痰憎、鍵盤出現(xiàn)、app前后臺的出現(xiàn)等攀涵,傳遞的數(shù)據(jù)也多種铣耘,不僅可以傳遞字典參數(shù)還可以傳遞對象參數(shù)
  • KVO通常用來監(jiān)聽某屬性值的變化,它可以記錄新舊值
  • 兩者都是MVC模式下以故,實現(xiàn)UI和數(shù)據(jù)分離的手段

2蜗细、和delegate對比?

  • 通知使用起來更簡潔怒详,邏輯清晰
  • 通知適用于一對多的情況炉媒,它會給每一個存在的對象發(fā)布消息,這種廣播式的發(fā)送消息意味著開銷的增大
  • delegate適用于一對一的情況昆烁,明確知道delegate是誰的代理吊骤,而又是誰去實現(xiàn)代理協(xié)議
  • 兩者的使用視情況而定,都是實現(xiàn)解耦的解決方案
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末静尼,一起剝皮案震驚了整個濱河市白粉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鼠渺,老刑警劉巖鸭巴,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拦盹,居然都是意外死亡鹃祖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門掌敬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惯豆,“玉大人,你說我怎么就攤上這事奔害】蓿” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵华临,是天一觀的道長芯杀。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么揭厚? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任却特,我火速辦了婚禮,結(jié)果婚禮上筛圆,老公的妹妹穿的比我還像新娘裂明。我一直安慰自己,他們只是感情好太援,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布闽晦。 她就那樣靜靜地躺著,像睡著了一般提岔。 火紅的嫁衣襯著肌膚如雪仙蛉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天碱蒙,我揣著相機(jī)與錄音荠瘪,去河邊找鬼。 笑死赛惩,一個胖子當(dāng)著我的面吹牛哀墓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坊秸,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼麸祷,長吁一口氣:“原來是場噩夢啊……” “哼澎怒!你這毒婦竟也來了褒搔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤喷面,失蹤者是張志新(化名)和其女友劉穎星瘾,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惧辈,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡琳状,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盒齿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片念逞。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖边翁,靈堂內(nèi)的尸體忽然破棺而出翎承,到底是詐尸還是另有隱情,我是刑警寧澤符匾,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布叨咖,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏甸各。R本人自食惡果不足惜垛贤,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望趣倾。 院中可真熱鬧聘惦,春花似錦、人聲如沸儒恋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽碧浊。三九已至涂邀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間箱锐,已是汗流浹背比勉。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留驹止,地道東北人浩聋。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像臊恋,于是被迫代替她去往敵國和親衣洁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • NSNotificationCenter對象(通知中心)提供了在程序中廣播消息的機(jī)制抖仅,它實質(zhì)上就是一個通知分發(fā)表坊夫。...
    9de75b652cd9閱讀 751評論 0 1
  • 轉(zhuǎn)載自南峰子的技術(shù)博客 一個NSNotificationCenter對象(通知中心)提供了在程序中廣播消息的機(jī)制,...
    我消失1314閱讀 880評論 0 2
  • 一個NSNotificationCenter對象(通知中心)提供了在程序中廣播消息測機(jī)制,它實質(zhì)上就是一個通知分發(fā)...
    DomAndMona閱讀 807評論 0 2
  • iOS 提供了一種 “同步的” 消息通知機(jī)制NSNotificationCenter撤卢,觀察者只要向消息中心注冊环凿, ...
    MasterChen閱讀 2,200評論 4 16
  • 前言: 1.HTML5的發(fā)展非常迅速,可以說已經(jīng)是前端開發(fā)人員的標(biāo)配放吩,在電商類型的APP中更是運(yùn)用廣泛智听,這個系列的...
    珍此良辰閱讀 9,693評論 10 21