通知NSNotificationCenter詳解(一)

版本記錄

版本號(hào) 時(shí)間
V1.0 2017.07.17

前言

與代理相比,通知具有低耦合的特點(diǎn),兩個(gè)毫無(wú)關(guān)聯(lián)的控制器之間可以進(jìn)行相互通信并相應(yīng)操作,用了通知很久,但是從沒(méi)有系統(tǒng)的總結(jié)一下通知相關(guān)的知識(shí)和遇到的坑,下面就講一下通知的相關(guān)知識(shí),先從簡(jiǎn)單的知識(shí)點(diǎn)和API開(kāi)始。

通知基礎(chǔ)

通知是ios中的一種消息機(jī)制,觀察者只要向消息中心注冊(cè), 即可接受其他對(duì)象發(fā)送來(lái)的消息,消息發(fā)送者和消息接受者兩者可以互相一無(wú)所知,完全解耦。這種消息通知機(jī)制可以應(yīng)用于任意時(shí)間和任何對(duì)象,觀察者可以有多個(gè),所以消息具有廣播的性質(zhì),只是需要注意的是,觀察者向消息中心注冊(cè)以后,在不需要接受消息時(shí)需要向消息中心注銷,這種消息廣播機(jī)制是典型的“Observer”(觀察者)模式。

消息機(jī)制常常用于在向服務(wù)器端請(qǐng)求數(shù)據(jù)或者提交數(shù)據(jù)的場(chǎng)景,在和服務(wù)器端成功交互后,需要處理服務(wù)器端返回的數(shù)據(jù),或發(fā)送響應(yīng)消息等,就需要用到消息機(jī)制。其原理主要如下所示:

通知原理

API

下面我們看一下ios中通知相關(guān)的API。

NSNotification

/****************   Notifications   ****************/

@interface NSNotification : NSObject <NSCopying, NSCoding>

@property (readonly, copy) NSNotificationName name;
@property (nullable, readonly, retain) id object;
@property (nullable, readonly, copy) NSDictionary *userInfo;

- (instancetype)initWithName:(NSNotificationName)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo NS_AVAILABLE(10_6, 4_0) NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;

@end

@interface NSNotification (NSNotificationCreation)

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

- (instancetype)init /*NS_UNAVAILABLE*/;    /* do not invoke; not a valid initializer for this class */

@end

這里面有幾點(diǎn):

  • name:通知的名字,其實(shí)就是為通知起的別名,作用就是用以區(qū)分不同通知,如果為nil標(biāo)識(shí)可以接收任何名字的通知。
  • object :發(fā)送通知的對(duì)象,用以區(qū)分是誰(shuí)發(fā)出的通知,如果為nil,表示可以接受任何對(duì)象發(fā)送的通知。
  • userInfo:它是一個(gè)字典用來(lái)存儲(chǔ)發(fā)送的通知信息,當(dāng)我們post一個(gè)通知的時(shí)候,就可以存放在字典里面,add監(jiān)聽(tīng)端,就可以將這個(gè)userInfo取出來(lái),得到通知的內(nèi)容。
  • 接下里的幾個(gè)對(duì)象方法和類方法中存儲(chǔ)的就是通知的初始化或者實(shí)例化方法。

** NSNotificationCenter**

/****************   Notification Center ****************/

@interface NSNotificationCenter : NSObject {
    @package
    void *_impl;
    void *_callback;
    void *_pad[11];
}

#if FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
@property (class, readonly, strong) NSNotificationCenter *defaultCenter;

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;
#endif

- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;

- (id <NSObject>)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block NS_AVAILABLE(10_6, 4_0);
    // The return value is retained by the system, and should be held onto by the caller in
    // order to remove the observer with removeObserver: later, to stop observation.

@end

這里涉及到的就是通知的轉(zhuǎn)發(fā)、監(jiān)聽(tīng)以及移除等,這個(gè)后續(xù)會(huì)詳細(xì)說(shuō)明。


通知的發(fā)送

有關(guān)通知發(fā)送的方法主要有三個(gè),如下:

- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

我們先說(shuō)一下相關(guān)參數(shù),這里的參數(shù)和注冊(cè)觀察者時(shí)候的參數(shù)也都是一樣的,說(shuō)一遍就不多說(shuō)了。

  • notification:通知對(duì)象,通知中心發(fā)出的對(duì)象就是它。
  • aName:通知的名字,用以區(qū)分不同通知,在注冊(cè)觀察者的時(shí)候,傳nil表示可以監(jiān)聽(tīng)任何名稱的通知。
  • anObject:發(fā)送通知的對(duì)象,如果傳nil表示不關(guān)心是誰(shuí)發(fā)送的通知,觀察者那邊傳入nil表示可以接受任何發(fā)送者的通知。
  • aUserInfo:通知消息,是一個(gè)字典,發(fā)送的內(nèi)容可以寫(xiě)在里面。

第一種發(fā)送通知

    //第一種發(fā)送通知
    NSNotification *notification = [NSNotification notificationWithName:@"notificationTestOne" object:self];
    [[NSNotificationCenter defaultCenter] postNotification:notification];
  

這里的object也可以為nil,表示不區(qū)分是誰(shuí)發(fā)送的。

第二種發(fā)送通知

    //第二種發(fā)送通知
    [[NSNotificationCenter defaultCenter] postNotificationName:@"notificationTestTwo" object:self];

同上,就不多說(shuō)了。

第三種發(fā)送通知

    //第三種發(fā)送通知
    NSDictionary *notiDict = @{@"key":@"content"};
    [[NSNotificationCenter defaultCenter] postNotificationName:@"notificationTestThree" object:self userInfo:notiDict];

這里,當(dāng)沒(méi)有什么傳遞的時(shí)候,userInfo可以為空,為空的時(shí)候就和前兩種發(fā)送通知是一樣的了。


通知的監(jiān)聽(tīng)

通知是一種觀察者模式,有人發(fā)送就要有人observer,并調(diào)用相關(guān)方法,處理相關(guān)邏輯。下面我們就接受一下上面三種發(fā)送的通知。

第一種監(jiān)聽(tīng)通知

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processTestOne:) name:@"notificationTestOne" object:nil];
- (void)processTestOne:(NSNotification *)noti
{
    NSLog(@"notificationTestOne");
}

我們看輸出

2017-07-17 16:18:57.708 JJNotification[17071:1508348] notificationTestOne

可見(jiàn),可以收到通知。

第二種監(jiān)聽(tīng)通知

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processTestTwo:) name:@"notificationTestTwo" object:nil];

- (void)processTestTwo:(NSNotification *)noti
{
    NSLog(@"notificationTestTwo");
}

下面看輸出

2017-07-17 16:24:20.773 JJNotification[17096:1537087] notificationTestTwo

可見(jiàn),可以收到通知。

第三種監(jiān)聽(tīng)通知

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processTestThree:) name:@"notificationTestThree" object:nil];
- (void)processTestThree:(NSNotification *)noti
{
    NSDictionary *notiDict = noti.userInfo;
    NSString *content = [notiDict objectForKey:@"key"];
    NSLog(@"notificationTestThree = %@",content);
}

下面看輸出

2017-07-17 16:24:20.773 JJNotification[17096:1537087] notificationTestThree = content

可見(jiàn),還是可以監(jiān)聽(tīng)到通知。


通知的移除

不用的監(jiān)聽(tīng)通知要移除,移除通知一般都是在delloc中完成,在delloc中可以移除全部監(jiān)聽(tīng)的通知,還可以移除指定名字的通知。

移除全部通知


- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

如果這么寫(xiě),那么上面三個(gè)notificationTestOnenotificationTestTwo、notificationTestThree通知都會(huì)被移除,可謂一勞永逸。

移除指定名字的通知

但是有的時(shí)候的需求是只要移除指定的某個(gè)通知,而保留某一個(gè)或者幾個(gè)通知,具體如下所示:

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"notificationTestOne" object:nil];
}

這樣子就把名字為notificationTestOne的通知移除了,其他的通知還會(huì)起作用,保留著監(jiān)聽(tīng)的功能。

后記

這里寫(xiě)的就是ios API以及通知的監(jiān)聽(tīng)、發(fā)送以及移除等基本知識(shí),目的就是給新手能看明白,后面的幾篇我會(huì)加入稍微難一點(diǎn)的東西還有就是一些通知過(guò)程中碰到的坑。

風(fēng)景
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 概述 在多數(shù)移動(dòng)應(yīng)用中任何時(shí)候都只能有一個(gè)應(yīng)用程序處于活躍狀態(tài),如果其他應(yīng)用此刻發(fā)生了一些用戶感興趣的那么通過(guò)通知...
    莫離_焱閱讀 6,564評(píng)論 1 8
  • 點(diǎn)擊查看原文 Web SDK 開(kāi)發(fā)手冊(cè) SDK 概述 網(wǎng)易云信 SDK 為 Web 應(yīng)用提供一個(gè)完善的 IM 系統(tǒng)...
    layjoy閱讀 13,945評(píng)論 0 15
  • 轉(zhuǎn)載自南峰子的技術(shù)博客 一個(gè)NSNotificationCenter對(duì)象(通知中心)提供了在程序中廣播消息的機(jī)制,...
    我消失1314閱讀 916評(píng)論 0 2
  • NSNotificationCenter對(duì)象(通知中心)提供了在程序中廣播消息的機(jī)制,它實(shí)質(zhì)上就是一個(gè)通知分發(fā)表。...
    9de75b652cd9閱讀 764評(píng)論 0 1
  • 一個(gè)NSNotificationCenter對(duì)象(通知中心)提供了在程序中廣播消息測(cè)機(jī)制,它實(shí)質(zhì)上就是一個(gè)通知分發(fā)...
    DomAndMona閱讀 822評(píng)論 0 2