iOS 关于NSNotification的一些总结

本文参考

苹果文档 Notification Programming Topics

苹果文档 NSNotificationCenter

iOS NSNotification详解


本文目录
  • 概述
  • 1.NSNotification
    • 1.1 创建NSNotification对象
  • 2.NSNotificationCenter
    • 2.1 通知中心的作用
    • 2.2 通知中心的分类
    • 2.3 NSNotificationCenter 的使用
    • 2.4 NSNotificationCenter的方法
    • 2.5 注册Observer的方法
    • 2.6 发布通知(NSNotification)
    • 2.7 注销Observer的方法
  • 3.NSNotificationQueue
    • 3.1 创建通知队列方法
    • 3.2 往队列加入通知(发送通知)方法
    • 3.3 移除队列中的通知方法
    • 3.4 发送方式
    • 3.5 合并通知
  • 4.NSNotificatinonCenter实现原理

博文配图

概述

The standard way to pass information between objects is message passing—one object invokes the method of another object. However, message passing requires that the object sending the message know who the receiver is and what messages it responds to. At times, this tight coupling of two objects is undesirable—most notably because it would join together two otherwise independent subsystems. For these cases, a broadcast model is introduced: An object posts a notification, which is dispatched to the appropriate observers through an NSNotificationCenter object, or simply notification center.

在对象之间传递消息的标准方式是:一个对象调用另一个对象的方法。然而,消息传递要求发送消息的对象需要知道接收者是谁以及谁来响应它,这会使两个独立的子系统紧密地耦合起来。

为了解决这种情况,引入了广播模式对象发布通知,通过 NSNotificationCenter 来派发通知给观察者。这样,对象根本就不需要知道观察者的存在

通知和delegate的区别

  • 任何数量的对象都可以接受通知,而不仅仅是delegate对象。也就是说,****通知是多对多的,而delegate是一对一的****。
  • 对象可以从 NSNotificationCenter 中接受任何消息,而不仅仅是预定义的代理方法
  • 发布通知的对象不需要知道观察者的存在

1. NSNotification

NSNotification:它是通知中心向所有观察者发布广播信息的容器

一个NSNotification对象包含三个属性:

  • name:通知的名称
  • object:发布通知的对象
  • dictionary:这个是可选的,为通知传递的字典信息。

1.1 创建NSNotification对象

+ (instancetype)notificationWithName:(NSString *)aName object:(id)anObject;
+ (instancetype)notificationWithName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
- (instancetype)initWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo;

实际上,在发布通知的时候,一般都不会去创建一个通知对象,而是使用通知中心直接发布

2. NSNotificationCenter

2.1 通知中心的作用

NSNotificationCenter(通知中心)是用来管理通知的接收和发送的。一个对象发送通知给通知中心,然后通知中心会将这个通知发送给观察者

2.2 通知中心的分类

通知中心有两类

  • NSNotificationCenter:这个是用来管理单个进程上的通知
  • NSDistributedNotificationCenter:这个是用来管理一台计算机上多个进程间的通知

2.3 NSNotificationCenter 的使用

一个进程都会有一个默认的通知中心,你可以使用下列方法获得它

[NSNotificationCenter defaultCenter];

2.4 NSNotificationCenter的方法

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

//注册观察者
- (void)addObserver:(id)observer selector:(SEL)aSelector 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);

//发布通知
- (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;

注意点

  1. NSNotificationCenter 会同步传递通知给观察者,也就是说,当一个对象发送通知后,必须等到观察者接收到并处理完这个通知后,这个对象发送通知才会返回;

  2. 如果想异步发布通知,使用 NotificationQueue;

  3. 在多线程中,通知总是在发布通知的线程中被传递,这个可能与观察者注册的线程不同;

2.5 注册Observer的方法

方法1,SEL方式:

使用以下方法可以向通知中心添加一个Observer

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

参数

  • observer:注册为观察者的对象
  • aSelector:观察者收到通知后,回调的方法。这个方法有且仅有一个参数,就是NSNotification对象
  • aName:通知的名称,即观察者要接收的通知的名称。如果aName为nil的话,那么所有的通知到会到达这个观察者
  • anObject:通知的发布者也就是说,指定了anObject后,只有这个对象发布的通知才会派发给观察者

方法2,block方式:

- (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);

参数

  • name:通知的名称,观察者想要接收的通知名称;
  • obj:通知的发布者。也就是说,指定了anObject后,只有这个对象发布的通知才会派发给观察者;
  • queue:block被添加进的 NSOperationQueue 队列。如果为空,block将会在发布线程中同步执行;
  • block:观察者接收到通知后要执行的任务。

2.6 发布通知(NSNotification)

通知中心(NSNotificationCenter)提供了相应的方法来帮助发布通知。

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

注意:

  • 参数anObject为发布通知的对象
  • 如果在子线程发布通知,那么也会在子线程通知观察者
  • 发布通知为同步操作,只有在观察者接收到并处理完这个通知后,才会返回往下执行。

2.7 注销Observer的方法

通知中心提供了对应的方法来注销观察者。

通知中心不会持有(retain)观察者对象,在通知中心注册过的对象,必须在该对象释放前取消注册。否则,当相应的通知再次出现时,通知中心仍然会向该监听器发送消息。因为相应的监听器对象已经被释放了,所以可能会导致应用崩溃

方法1:
- (void)removeObserver:(id)observer;

这个方法可以移除观察者对象。但是最好不要在 delloc方法 之前使用,因为这个对象如果是长期存在的话,也可能被其它的代码注册为了观察者。所以要在delloc销毁这个对象的时候,去移除这个观察者对象

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
方法2:
- (void)removeObserver:(id)observer name:(NSNotificationName)aName object:(id)anObject;

参数
name:通知的名称;
anobject:发布通知的对象。

这个方法可以通过name和anobject参数移除特定的观察者对象。

3. NSNotificationQueue

发布通知是同步执行的,只有在观察者对象接收到并处理完这个通知后才会往下执行。要想异步发布通知,就需要使用NSNotificationQueue。

NSNotificationQueue:通知队列,用来管理多个通知的调用。通知队列通常以先进先出(FIFO)顺序维护NSNotificationQueue就像一个缓冲池把一个个通知放进池子中,使用特定方式通过NSNotificationCenter发送到相应的观察者

3.1 创建通知队列方法

- (instancetype)initWithNotificationCenter:(NSNotificationCenter *)notificationCenter NS_DESIGNATED_INITIALIZER;

3.2 往队列加入通知(发送通知)方法

- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle;
 
- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle coalesceMask:(NSNotificationCoalescing)coalesceMask forModes:(nullable NSArray<NSRunLoopMode> *)modes;

3.3 移除队列中的通知方法

- (void)dequeueNotificationsMatching:(NSNotification *)notification coalesceMask:(NSUInteger)coalesceMask;

3.4 发送方式

NSPostingStyle包括三种类型:

typedef NS_ENUM(NSUInteger, NSPostingStyle) {
    NSPostWhenIdle = 1,
    NSPostASAP = 2,
    NSPostNow = 3  
};
  • NSPostWhenIdle:空闲发送通知,当RunLoop处于等待或空闲状态时,发送通知,对于不重要的通知可以使用。
  • NSPostASAP:尽快发送通知,当前RunLoop迭代完成时,通知将会被发送,有点类似没有延迟的定时器。
  • NSPostNow :同步发送通知,如果不使用合并通知和postNotification:一样是同步通知。

3.5 合并通知

NSNotificationQueue除了有异步通知的能力之外,也能对当前队列的通知根据NSNotificationCoalescing类型进行合成(即将几个合成一个)

NSNotificationCoalescing也包括三种类型:

typedef NS_OPTIONS(NSUInteger, NSNotificationCoalescing) {
    NSNotificationNoCoalescing = 0,
    NSNotificationCoalescingOnName = 1,
    NSNotificationCoalescingOnSender = 2
};

NSNotificationNoCoalescing:不合并通知。
NSNotificationCoalescingOnName:合并相同名称的通知(NSNotification的name相同)。
NSNotificationCoalescingOnSender:合并同一对象的通知(NSNotificationobject相同)。

通过合并我们可以用来保证相同的通知只被发送一次

forModes:(nullable NSArray<NSRunLoopMode> *)modes

可以使用不同的NSRunLoopMode配合来发送通知,可以看出实际上NSNotificationQueue与RunLoop的机制以及运行循环有关系,通过NSNotificationQueue队列来发送的通知和关联的RunLoop运行机制来进行的。

4. NSNotificatinonCenter实现原理

NSNotificatinonCenter用来管理通知的接收和发送。将观察者注册到NSNotificatinonCenter的通知调度表中,然后发送通知时利用标识符name和object识别出调度表中的观察者,然后调用相应的观察者的方法,即传递消息(在Objective-C中对象调用方法,就是传递消息,消息有name或者selector,可以接受参数,而且可能有返回值),如果是基于block创建的通知就调用NSNotification的block

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

推荐阅读更多精彩内容