1. 前语 在OC中有一种音讯播送机制,该机制能够向注册到Notification Center的Observe发送音讯。其流程能够简单用下图表明。

Objective-C SDK之NSNotificationCenter

  1. Observer注册到Notification Center
  2. Poster 发送音讯到Notification Center
  3. Notification Center根据Poster发送的音讯查找其保护的dispatch table
  4. 假如找到相对应的Observer需求的音讯,那么将该音讯播送至Observer
  5. Observer承受到音讯,履行相对应的Action
  6. Notification Center将Observer移出 在音讯告诉机制中,需求重视三个人物Notification Center,Observer,Poster。
  • Notification Center是一个音讯告诉机制,能够将音讯播送至注册的observer。
  • Observer 将其注册至Notification Center,能够承受相对应的音讯,而且接纳音讯之后履行相对应的动作。
  • Poster 将音讯发送至Notification Center。 需求注意的是每一个running app 都有一个名为defaultCenter的notification center,你也能够创立一个新的notificaion center。此外,notification center能够传递音讯在一个程序中,也能够在多个进程中传递音讯。假如需求在多个进程中传递告诉,能够运用NSDistributedNotificationCenter。

2. addObserver

向notification center中添加Observer有如下办法。

- (void)addObserver:(id)observer selector:(SEL)aSelector
                    name:(NSNotificationName)aName 
                    object:(id)anObject;
observer:观察者目标
selector:接纳音讯后履行的办法,且该办法只有一个参数形如:-(void)acceptNotificationAction:(NSNotification *)noic;
name:音讯称号,当为nil时,不作为查找dispatch table的匹配特点。
obejct:接纳哪个目标发送的音讯,当为nil时,不作为查找dispatch table的匹配特点。
- (id<NSObject>)addObserverForName:(NSNotificationName)name
                 object:(id)obj 
                 queue:(NSOperationQueue *)queue 
                 usingBlock:(void (^)(NSNotification *note))block;
name:音讯称号,当为nil时,不作为查找dispatch table的匹配特点。
object:接纳哪个目标发送的音讯,当为nil时,不作为查找dispatch table的匹配特点。
queue:指定block的运转的queue,当queue为nil时,block默许同步运转在poster地点线程
usingBlock:履行的block,能够理解为observer block。
该办法回来一个不透明的目标,用来代表observer。Notification Center坚持该目标一直到移除observer registration。

当你运用addObserverForName:(NSNotificationName)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block办法注册observer,而且只接纳一次音讯。能够运用如下的代码。

NSNotificationCenter * __weak center = [NSNotificationCenter defaultCenter];
id __block token = [center addObserverForName:@"OneTimeNotification"
                                       object:nil
                                        queue:[NSOperationQueue mainQueue]
                                   usingBlock:^(NSNotification *note) {
                                       NSLog(@"Received the notification!");
                                       [center removeObserver:token];
                                   }];

3. removeObserver

将观察者从notification center中移除,而且不在承受音讯告诉,能够运用如下办法。

- (void)removeObserver:(id)observer
                  name:(NSNotificationName)aName 
                object:(id)anObject;
observe:观察者目标,dispacth table中移除观察者目标为observer的条目。
aName:音讯称号 dispacth table中移除音讯称号为aName的条目。假如为nil,则不作为查找dispatch table的匹配特点。
anObject:发送音讯的目标,dispacth table中移除发送音讯的目标为anObject的条目。假如为nil,则不作为查找dispatch table的匹配特点。
- (void)removeObserver:(id)observer;
observer:观察者目标,dispacth table中移除观察者目标为observer的条目。

在你removeObserver的时候,有必要保证addObserve办法中的指定目标存在。当你运用(iOS 9.0及今后,macOS 10.11及今后)addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject进行observer registration,你不需求运用removerObserver来unregister observer,系统会在下次对其发送音讯时,会将其移除。 当你unregister observer时,假如你register observer时指定了音讯称号以及音讯的发送者,那么最好在unregister observer时最好运用下面的办法。

- (void)removeObserver:(id)observer
                  name:(NSNotificationName)aName 
                object:(id)anObject;
observe:观察者目标,dispacth table中移除观察者目标为observer的条目。
aName:音讯称号 dispacth table中移除音讯称号为aName的条目。假如为nil,则不作为查找dispatch table的匹配特点。
anObject:发送音讯的目标,dispacth table中移除发送音讯的目标为anObject的条目。假如为nil,则不作为查找dispatch table的匹配特点。

4. postNotification

发送音讯至notification center,有三种办法。其中最简单的办法是

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

第二种是指定音讯称号,音讯发送者,以及音讯额外的信息。

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

最后一个相当于将第二种发送音讯的办法的参数aUserInfo设置为nil。

- (void)postNotificationName:(NSNotificationName)aName
                      object:(id)anObject;

5. 代码实践

界说如下两个类NotificationA和NotificationB。代码如下: 类NotificationA界说如下:

//NotificationA.h 
#ifndef NotificationA_h
#define NotificationA_h
@class NotificationB;
@interface NotificationA : NSObject
@property (weak) NotificationB *B;
- (void)removeObserver;
- (void)activeForNotification:(NSNotification *)notification;
- (void)postNotification;
- (void)addOberver;
@end
#endif /* NotificationA_h */

//NotificationA.m 
#import <Foundation/Foundation.h>
#import "NotificationA.h"
#import "NotificationB.h"
@implementation NotificationA
- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"A Send" object:self];
}
- (void)activeForNotification:(NSNotification *)notification{
    NSLog(@"Accept notificaion from B");
}
- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:nil];
}
- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"B Send" object:nil];
}
@end

类NotificationB界说如下:

// NotificationB.h
#ifndef NotificationB_h
#define NotificationB_h
@class NotificationA;
@interface NotificationB : NSObject
@property (weak) NotificationA *A;
- (void)removeObserver;
- (void)activeForNotification:(NSNotification *)notification;
- (void)postNotification;
- (void)addOberver;
@end
#endif /* NotificationB_h */
// NotificationB.m
@implementation NotificationB
- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" object:self];
}
- (void)activeForNotification:(NSNotification *)notification{
    NSLog(@"Accept notificaion from A");
}
- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"A Send" object:self.A];
}
- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"A Send" object:nil];
}
@end

两个类都有下面的四个办法。

- (void)removeObserver;
- (void)activeForNotification:(NSNotification *)notification;
- (void)postNotification;
- (void)addOberver;

首先利用NotificationA目标作为Observer,NotificationB作为Nofication Poster。 main函数如下:

int main(int argc, const char * argv[]) {
    NotificationA *A = [[NotificationA alloc] init];
    NotificationB *B = [[NotificationB alloc] init];
    A.B = B;
    B.A = A;
    [A addOberver];
    [B postNotification];
    return 0;
}

在类NotificationA中的addObserver中,register observer代码如下:name不为空,object为空。

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:nil];
}

在类NotificationB中的postNotification中,name不为空,object也不为空。

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"A Send" object:self];
}

输出成果如下:能够看出,observer接纳到了音讯,履行了activeForNotification办法。

Objective-C SDK之NSNotificationCenter
假如在类NotificationB中的postNotification中,name不为空,object也为空。

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"A Send" object:nil];
}

输出成果如下:能够看出,observer接纳到了音讯,履行了activeForNotification办法。

Objective-C SDK之NSNotificationCenter

当register observer时,指定了notification name时,当post notification时,不管指定或不指定notificaion poster。observer都能承受到音讯

那么接着咱们addobserver时指定发送音讯的目标,且不指定notification name。代码如下: 类NotificationA的中addObserver函数如下:

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:nil object:self.B];
}

而此刻类NotificationB的中postNotificaion函数如下:指定了object为self,notification name为nil。

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:“B Sendobject:self];
}

输出成果如下:能够看出,observer接纳到了音讯,履行了activeForNotification办法。

Objective-C SDK之NSNotificationCenter
可是假如notification name为nil呢,虽然此刻编译器只会给一个正告(该参数是一个non-null argument),可是observer现已承受不到音讯。 代码如下:

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:nil object:self];
}

输出成果如下:能够看出,observer没有接纳到音讯。

Objective-C SDK之NSNotificationCenter

假如postNotification办法没有指定或许与指定的notificaion poster不对应,也无法承受到音讯。

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" object:nil];
}
或
- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" object:[[NSString alloc] init]];
}

Objective-C SDK之NSNotificationCenter

当register observer时,指定了object,没有指定notification name。当post notification时,notification name有必要指定, 且poster object有必要与register obberver指定object的相同,这样observer才干承受到音讯

咱们能够运用removerObserver来unregister Observer, 当removerObserver时指定了notification name,不管addObserver时,object是否指定。在dispatch table中包含该notification name的条目都会被remove。 代码如下: 类NotificationA中addObserver代码如下:

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:self.B];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:nil];
}

类NotificationA中removeObserver办法代码如下:

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

类NotificationB中postNotification办法代码如下:

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" object:[[NSString alloc] init]];
}

mian函数代码如下:

int main(int argc, const char * argv[]) {
    NotificationA *A = [[NotificationA alloc] init];
    NotificationB *B = [[NotificationB alloc] init];
    A.B = B;
    B.A = A;
    [A addOberver];
    [A removeObserve];
    [B postNotification];
    return 0;
}

成果如下:能够看出没有任何输出,说明removeObserver中指定了notification name,会将dispatch table中包含该notification name的条目都会被remove。

Objective-C SDK之NSNotificationCenter

再看一个例子,当removerObserver时指定了poster object, 代码如下: 类NotificationA中addObserver代码如下:

- (void)addOberver{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:nil object:self.B];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeForNotification:) name:@"B Send" object:self.B];
}

类NotificationA中removeObserver办法代码如下:

- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@“Test”object:self.B];
}

类NotificationB中postNotification办法代码如下:

- (void)postNotification{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"B Send" object:self]];
}

mian函数代码如下:

int main(int argc, const char * argv[]) {
    NotificationA *A = [[NotificationA alloc] init];
    NotificationB *B = [[NotificationB alloc] init];
    A.B = B;
    B.A = A;
    [A addOberver];
    [A removeObserve];
    [B postNotification];
    return 0;
}

成果如下:removeObserver没有生效,observer仍然接纳到了音讯。

Objective-C SDK之NSNotificationCenter
当removeObserver代码如下: 类NotificationA中removeObserver办法代码如下:

- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:self.B];
}

成果如下:能够看出,observer被移除,且承受不到音讯。那么removeObserver移除音讯的原则是:指定了object和name,在dispatch table中查找条目,这两项都共同的条目被移除。不然不移除。假如只指定name或object,则在dispatch table中寻觅满意这一项的条目移除。

Objective-C SDK之NSNotificationCenter
那Observer是不是也要在removerObserver中满意呢,将removeObserver代码改写如下:

- (void)removeObserver{
    [[NSNotificationCenter defaultCenter] removeObserver:[[NSString alloc] init] name:nil object:self.B];
}

成果如下:能够看出,假如removeObserver办法指定observer目标,在dispatch table没有找到对应的条目,则也无法移除observer。

Objective-C SDK之NSNotificationCenter
总结:在dispatch table中包含三个匹配项:

  • Observer
  • Notification Name
  • Notification Poster 当register observer指定的这三项,remove Observer指定的三项满意才干在dispatch table中移除Observer,也就是Observer不能承受到音讯。 当register observer指定的这三项,当你指定了notification name和notification 时时,postNotification指定的这两项需求坚持共同。但只指定了notification 或 notification poster时,postnotification只需满意对应项共同,Observer就能够承受到音讯。

6 总结

  1. notification center保持了一张dispatch table,其主要三项包含:Observer,Notification,Notification Poster。
  2. 当addObserver,指定了这三项时,removerObserver指定的这三项有必要与addObserver指定的这三项一一对应才干从dispatch table移除。
  3. 当addObserver,指定了notification name和poster object不为空,则postNotification这两项都有必要与其共同,Observer才干承受到音讯。当只是指定了notificationname,poster object为空。则postNotification的notification name参数,有必要与其共同,object参数则能够恣意。当只指定了poster object。则postNotification的notification name(是一个non-null argument)有必要指定,且poster obejct有必要与其共同,Observer才干承受音讯。