深入NSNotification(iOS)

NSNotification顾名思义就是通知的作用,一个对象通知另外一个对象,可以用来传递参数、通信等作用,与delegate的一对一不同,通知是一对多的。在一个对象中注册了通知,那么其他任意对象都可以来对这个对象发出通知。
这篇文章主要讲诉两个对象

  • NSNotificationCenter
  • NSNotificationQueue

1、NSNotificationCenter

    /**
     *  注册一个通知
     *
     */
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getNotification:) name:@"notificationMethon" object:nil];

NSNotificationCenter是一个单列,我们可以通过defaultCenter来获取到通知中心这个单列,使用通知的第一步就是添加通知。

 /**
     *  移除所有通知
     */
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    /**
     *  移除单个通知
     *
     */
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"notificationMethon" object:nil];

需要注意的是当我们添加一个通知以后,必须在合适的位置将通知移除,不然下次再添加这个通知并调用时,这个通知将会被调用多次,而这一般不是我们所预料的。一般我们在对象的析构函数中将通知移除,我们可以选择将这个对象中的所有通知移除,也可以选择一个一个按照通知的name来移除。

    /**
     *  发出通知
     */
    [[NSNotificationCenter defaultCenter] postNotificationName:@"notificationMethon" object:nil userInfo:@{@"key":@"value"}];

当我们添加通知以后,我们就可以发出通知,也是通过NSNotificationCenter类的defaultCenter来获取到通知中心,然后通过postNotificationName来发出通知。
这里需要注意的一点就是这样发出的通知是同步操作,也就是只有当发出的通知执行完毕以后才会继续执行接下去的代码。

-(void)getNotification:(NSNotification *)info{
    NSDictionary *dict = info.userInfo;
}

这是发出通知以后会调用的方法,在多线程操作时,发出通知的对象和接收通知的对象处于同一个线程。
在这个响应的方法中有一个参数<code>(NSNotification *)info</code>这个参数是NSNotification类型的,这个类型有几个属性:

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

其中<code> userInfo </code>这个属性是一个字典,也是最为关键以及有用的属性,我们通过这个属性来传递参数等一些有用的信息。

总结以上内容,所以通知的最简单的使用过程就是:
1、添加通知;
2、发出通知;
3、移除通知;


2、NSNotificationQueue

上面说到<code> NSNotificationCenter</code>是一个同步操作,也就是只有当响应的通知的代码执行完毕以后,发出通知的对象的代码才会继续往下执行。那么<code> NSNotificationQueue</code>就有一些区别,他有两个非常重要的特点:即通告的聚结和异步发送。聚结是把和刚进入队列的通告相类似的其它通告从队列中移除的过程。如果一个新的通告和已经在队列中的通告相类似,则新的通告不进入队列,而所有类似的通告(除了队列中的第一个通告以外)都被移除。然而,您不应该依赖于这个特殊的聚结行为。
而异步发送则很好理解了,也就是说发出通知以后立刻返回,也就是是继续执行下面的代码,并不管通知发出后的具体情况

/**
     发出通知
     */
    NSNotification *notifacation = [[NSNotification alloc]initWithName:@"notificationMethon" object:nil userInfo:@{@"key":@"value1"}];
    [[NSNotificationQueue defaultQueue] enqueueNotification:notifacation postingStyle:NSPostWhenIdle];

我们可以通过,NSNotificationQueue的defaultQueue来获取到这个通知队列,然后调用<code>enqueueNotification</code>来发出通知,我们可以看到第二个参数<code>postingStyle</code>,这个参数是一个枚举,他可以是以下三个值:

typedef NS_ENUM(NSUInteger, NSPostingStyle) {
    NSPostWhenIdle = 1,
    NSPostASAP = 2,
    NSPostNow = 3
};

这三个不同的值是有一定区别的。(以下内容摘抄自网络)

尽快发送
以NSPostASAP风格进入队列的通告会在运行循环的当前迭代完成时被发送给通告中心,如果当前运行循环模式和请求的模式相匹配的话(如果请求的模式和当前模式不同,则通告在进入请求的模式时被发出)。由于运行循环在每个迭代过程中可能进行多个调用分支(callout),所以在当前调用分支退出及控制权返回运行循环时,通告可能被分发,也可能不被分发。其它的调用分支可能先发生,比如定时器或由其它源触发了事件,或者其它异步的通告被分发了。

您通常可以将NSPostASAP风格用于开销昂贵的资源,比如显示服务器。如果在运行循环的一个调用分支过程中有很多客户代码在窗口缓冲区中进行描画,在每次描画之后将缓冲区的内容刷新到显示服务器的开销是很昂贵的。在这种情况下,每个draw...方法都会将诸如“FlushTheServer” 这样的通告排入队列,并指定按名称和对象进行聚结,以及使用NSPostASAP风格。结果,在运行循环的最后,那些通告中只有一个被派发,而窗口缓冲区也只被刷新一次。

空闲时发送
以NSPostWhenIdle风格进入队列的通告只在运行循环处于等待状态时才被发出。在这种状态下,运行循环的输入通道中没有任何事件,包括定时器和异步事件。以NSPostWhenIdle风格进入队列的一个典型的例子是当用户键入文本、而程序的其它地方需要显示文本字节长度的时候。在用户输入每一个字符后都对文本输入框的尺寸进行更新的开销是很大的(而且不是特别有用),特别是当用户快速输入的时候。在这种情况下,Cocoa会在每个字符键入之后,将诸如“ChangeTheDisplayedSize”这样的通告进行排队,同时把聚结开关打开,并使用NSPostWhenIdle风格。当用户停止输入的时候,队列中只有一个“ChangeTheDisplayedSize”通告(由于聚结的原因)会在运行循环进入等待状态时被发出,显示部分也因此被刷新。请注意,运行循环即将退出(当所有的输入通道都过时的时候,会发生这种情况)时并不处于等待状态,因此也不会发出通告。

立即发送
以NSPostNow风格进入队列的通告会在聚结之后,立即发送到通告中心。您可以在不需要异步调用行为的时候 使用NSPostNow风格(或者通过NSNotificationCenter的postNotification:方法来发送)。在很多编程环境下,我们不仅允许同步的行为,而且希望使用这种行为:即您希望通告中心在通告派发之后返回,以便确定观察者对象收到通告并进行了处理。当然,当您希望通过聚结移除队列中类似的通告时,应该用enqueueNotification...方法,且使用NSPostNow风格,而不是使用postNotification:方法。

总结NSNotificationCenter和NSNotificationQueue的区别,也许最大的一点就是发出通知时一个是同步一个是异步。

如果对您有一定帮助,请关注本人。
(转载请表明出处、作者)

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

推荐阅读更多精彩内容