Objective-C 学习笔记 - 第12章 通知中心

Foundation框架含有一个 API 集合——支持通知类,这些类提供了功能强大的事件驱动编程机制。

通知

通知是指封装起来的事件信息。它可以发送给一个或多个观察对象,以回应应用程序中出现的事件。通知结构效仿了广播模型,因此能够将接收事件的对象与发送事件的对象解耦。使用通知支持类可以创建和传递通知、发送和接收通知,以及通过队列以异步方式传递通知。使用 NSNotification 类可以封装由通知对象发送的信息。其中,含有唯一名称、被传递的对象和补充信息的目录(可选)。

// 创建简单问候通知ApplicationDidHandleGreetingNotification
NSString * aName = @"ApplicationDidHandleGreetingNotification";
NSString * anObject = @"Hello World !";
NSNotification * notify = [NSNotification notificationWithName:aName
                                                        object:anObject];
// 发送通知
NSNotificationCenter * ncenter = [NSNotificationCenter defaultCenter];
[ncenter postNotification: notify];

// 创建并发送通知
[ncenter postNotificationName:aName
                       object:anObject];

// 注册观察者
Greeter *handler = [Greeter new];
[ncenter addObserver: handler
            selector:@selector(handlerGreeting:)
                name:aName
              object:nil];

// 注销已注册的观察者
[ncenter removeObserver: handler];
// 或者更加细腻的操作
[ncenter removeObserver: handler
                name:aName
              object:nil];

创建简单问候通知ApplicationDidHandleGreetingNotification,你可能好奇为什么这个通知的名称这么长?因为苹果公司提出了一些命名通知的指导原则,这些原则旨在方便创建带自我描述的、具有唯一性的通知名称:

  • 相关类的名称
  • 单词 Did 或 Will
  • 实现唯一性的名称成分
  • 单词 Notification

了解几个相关类

NSNotification 这个类可以理解为一个消息对象,其中有三个成员变量。

// 这个成员变量是这个消息对象的唯一标识,用于辨别消息对象
@property (readonly, copy) NSString *name;

// 这个成员变量定义一个对象,可以理解为针对某一个对象的消息
@property (nullable, readonly, retain) id object;

// 这个成员变量是一个字典,可以用其来进行传值
@property (nullable, readonly, copy) NSDictionary *userInfo;

// 初始化方法(官方文档有明确的说明,不可以使用init进行初始化)
- (instancetype)initWithName:(NSString *)name 
                      object:(nullable id)object 
                      userInfo:(nullable NSDictionary *)userInfo
+ (instancetype)notificationWithName:(NSString *)aName 
                              object:(nullable id)anObject;                             
+ (instancetype)notificationWithName:(NSString *)aName 
                              object:(nullable id)anObject 
                              userInfo:(nullable NSDictionary *)aUserInfo;

NSNotificationCenter 这个类是一个通知中心,使用单例设计,每个应用程序都会有一个默认的通知中心。用于调度通知的发送的接受。

// 注册通知观察者的方法
- (void)addObserver:(id)observer 
           selector:(SEL)aSelector 
               name:(nullable NSString *)aName 
             object:(nullable id)anObject;

// 发送通知消息的方法
- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSString *)aName 
                      object:(nullable id)anObject;                 
- (void)postNotificationName:(NSString *)aName 
                      object:(nullable id)anObject 
                    userInfo:(nullable NSDictionary *)aUserInfo;
                    
// 移除观察者的方法
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer 
                  name:(nullable NSString *)aName 
                object:(nullable id)anObject;

通知的使用流程

◉ 定义一个事件到来时该执行的方法:

// 接收通知事件的类必须实现一个拥有以下特征的通知处理器方法:
// - (void)方法名:(NSNotification *)通知;
- (void)execute:(NSNotification *)notification {
    // do something when received notification
    // notification.name is @"NOTIFICATION_NAME"
    if(notification.object && 
        [notification.object isKindOfClass:[Test class]]) {
        // do something
    }
}

◉ 注册观察者:

NSNotificationCenter * ncenter = [NSNotificationCenter defaultCenter];
[ncenter addObserver:self
            selector:@selector(execute:)
                name:@"NOTIFICATION_NAME"
              object:nil];

使用默认的通知中心,上面代码的意义的:观察者 self 在收到名为 @"NOTIFICATION_NAME" 的事件时执行 @selector(execute:),最后一个参数是表示会对哪个发送者对象发出的事件作出响应,nil 时表示接受所有发送者的事件。

◉ 注激发事件,即通知相应的观察者:

NSNotificationCenter * ncenter = [NSNotificationCenter defaultCenter];
[ncenter postNotificationName:@"NOTIFICATION_NAME"
                       object:nil];
// 或者用下面几行代码,明确的 notification 示例
Test *test = [[Test alloc] init];
NSNotification *notification = [NSNotification
            notificationWithName:@"NOTIFICATION_NAME"
                          object:test];
[ncenter postNotification:notification];

这里的 object 参数对应到方法 - (void)execute:(NSNotification *)notification 里的 notification.object, name 就是 notification.name。代码到这里,方法 - (void)execute:(NSNotification *)notification 就会得到执行了。

说明:我们上面用的 [NSNotificationCenter defaultCenter] 是默认的同一个实例,你也可以使用自己的 NSNotificationCenter,如:NSNotificationCenter *notificationCenter = [[NSNotificationCenter alloc]init];事件只会在当前的 NotificationCenter 中广播,不同的 NotificationCenter 之间的事件通知互不相干。

◉ 观察者如果对一些事件没兴趣了,应该从 NotificationCenter 中移除掉:

NSNotificationCenter * ncenter = [NSNotificationCenter defaultCenter];
[ncenter removeObserver:self 
                   name:@"NOTIFICATION_NAME"
                object:test]; // object与注册时相同

异步或合并通知

NSNotificationQueue 类可以为通知中心提供队列,因此使用此类可以通过异步方式发布或合并通知。合并通知是指(从队列中)过滤掉与较早加入队列的某个通知类似的通知的过程。

// 获取当前线程的默认通知队列
NSNotificationQueue *nqueue = [NSNotificationQueue defaultQueue];

// 为指定的通知中心创建通知队列
NSNotificationCenter *ncenter = [NSNotificationCenter defaultCenter];
NSNotificationQueue *queue = [[NSNotificationQueue alloc] 
                               initWithNotificationCenter:ncenter];

// 队列发布通知
// 下面代码以同步方式将变量 notif 中的通知添加到队列中,并合并了同名的通知
[[NSNotificationQueue defaultQueue]
    enqueueNotification:notif
           postingStyle:NSPostNow
           coalesceMask:NSNotificationCoalescingOnName
               forModes:nil];

// 队列删除通知
// 下面代码从执行合并操作的队列中删除变量 notif 中的通知
[[NSNotificationQueue defaultQueue]
    dequeueNotificationsMatching:notif
           coalesceMask:NSNotificationNoCoalescing];                   

方法 enqueueNotification:postingStyle:coalesceMask:forModes: 可以设置发布样式、合并选项和支持的发布通知运行模式。

可以使用下列常数定义合并选项:

  • NSNotificationNoCoalescing 不合并通知,记录所有通知
  • NSNotificationCoalescingOnName 合并同名的通知,即仅记录其中一条通知
  • NSNotificationCoalescingOnSender 合并来自同一发送者的通知,即仅记录其中一条通知

发布样式定义了将通知添加到队列中的交互模式(同步/异步、在空闲时/立刻)。可以使用下列常量设置这些选项:

  • NSPostASAP 当前的运行循环结束时,立刻以异步方式发布通知
  • NSPostWhenIdle 当运行循环等待输入数据或计时器事件时,以异步方式发布通知
  • NSPostNow 在合并后立刻发布队列中的通知,提供高效的同步行为。这类行为不需要依赖运行循环。

小结

本章介绍了 Foundation 框架的通知机制,简要介绍了与通知相关的类和 API,并介绍了使用通知的基本步骤。

你可能感兴趣的:(Objective-C 学习笔记 - 第12章 通知中心)