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

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

<h3 id="notify">通知</h3>

通知是指封装起来的事件信息。它可以发送给一个或多个观察对象,以回应应用程序中出现的事件。通知结构效仿了广播模型,因此能够将接收事件的对象与发送事件的对象解耦。使用通知支持类可以创建和传递通知、发送和接收通知,以及通过队列以异步方式传递通知。使用 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

<h3 id="notificationclass">了解几个相关类</h3>

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;

<h3 id="notificationuse">通知的使用流程</h3>

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

// 接收通知事件的类必须实现一个拥有以下特征的通知处理器方法:
// - (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与注册时相同

<h3 id="queuenotification">异步或合并通知</h3>

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 在合并后立刻发布队列中的通知,提供高效的同步行为。这类行为不需要依赖运行循环。

<h3 id="notificationsummary">小结</h3>

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容