iOS开发-消息传递方式-NotificationCenter

说完了target-action

说完了KVO

今天说另一种消息传递的方式,这种方式和KVO很像,通常也是用于一对多的情况,这种消息传递的方式就是NotificationCenter

NotificationCenter 翻译过来就是通知中心,他和我们生活中的广播很相似。

如何使用NotificationCenter

使用NotificationCenter和KVO非常相似,一般也是分为4个步骤:

  • 1.添加观察者。

  • 2.实现响应方法。

  • 3.发出通知。

  • 4.移除观察者。

一般在使用NotificationCenter时我们通常都是直接使用系统默认的NotificationCenter


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

使用类方法调用他之后,我们就可以做响应的添加、发出通知、移除等操作了。

添加观察者

添加观察者有两种方式,一个是直接调用函数添加,然后再编写实现的方法,通过selector来响应通知。

还有一种方法是使用block,在代码块内部实现响应通知的操作。

直接添加

直接添加观察者时可以通过函数:


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

传递了响应的参数之后就完成了观察者的添加,那我们来看看传递的参数都有什么作用。

observer

通知的观察者,当通知post出来之后,观察者会收到响应的通知,不可以为nil。

aSelector

收到通知之后需要做的操作,当通知post出来之后,会触发该方法,当中会传递一个NSNotification的参数。

aName

通知名称,用来区分发送通知的对象,可以为nil,但是因为应用的执行的过程中会发出很多通知,如果为nil则代表接受所有的通知。

anObject

发送的对象,也是用来区分发送通知的对象,可以为nil,当为nil时,也会接受同一通知名称的所有的通知。

一般情况下,如果我们将通知名称和发送对象都置为nil时,我们可以监听到当前通知中心的全部通知。比如:


- (void)addNotificationCenter

{

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationCall:) name:nil object:nil];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"postNotification" object:nil];

}

- (void)notificationCall:(NSNotification *)notification

{

 NSLog(@"notification = %@", notification.name);

}

上边一段代码执行了之后我们会发现结果如下:


2018-03-08 17:28:25.368264+0800 MessagePassingDemo[50635:3561130] notification = postNotification

2018-03-08 17:28:25.368593+0800 MessagePassingDemo[50635:3561130] notification = UINavigationControllerWillShowViewControllerNotification

2018-03-08 17:28:25.370494+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.370677+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.371431+0800 MessagePassingDemo[50635:3561130] notification = _UIWindowContentWillRotateNotification

2018-03-08 17:28:25.372607+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.372898+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.373097+0800 MessagePassingDemo[50635:3561130] notification = _UIWindowContentWillRotateNotification

2018-03-08 17:28:25.392586+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.393403+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.423827+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.424067+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.424322+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.424721+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.426606+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.426780+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.427223+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.427401+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.431615+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.790567+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.790769+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.791427+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.792659+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidCommitNotification

2018-03-08 17:28:25.793148+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.935701+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

2018-03-08 17:28:25.936635+0800 MessagePassingDemo[50635:3561130] notification = UINavigationControllerDidShowViewControllerNotification

2018-03-08 17:28:25.936938+0800 MessagePassingDemo[50635:3561130] notification = UIViewAnimationDidStopNotification

所以一般情况下,添加观察者时,我们至少都会指定好通知的名称。


- (void)addNotificationCenter

{

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationCall:) name:@"postNotification" object:nil];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"postNotification" object:nil];

}

- (void)notificationCall:(NSNotification *)notification

{

 NSLog(@"notification = %@", notification.name);

}

输出:


2018-03-08 17:30:22.767448+0800 MessagePassingDemo[50709:3564576] notification = postNotification

另外,如果我们设置了通知名,没有设置发送对象时,所有此通知名的通知都会被接收到,如果设置了发送对象:


- (void)addNotificationCenter

{

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationCall:) name:@"postNotification" object:self.buttonA];    

}

- (void)buttonAClicked

{

 [[NSNotificationCenter defaultCenter] postNotificationName:@"postNotification" object:self.buttonA];

}

- (void)buttonBClicked

{

 [[NSNotificationCenter defaultCenter] postNotificationName:@"postNotification" object:self.buttonB];

}

这时候就只有buttonAClickedbuttonA被点击时才会触发通知。

使用 block

使用block添加观察者时可以调用如下函数:


- (id <NSObject>)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));

相比较于上一个方法,这种方法中没有指定具体的观察者,并且用block代替了触发的方法,而且新增了一个queue

因为用block回调来替代了触发的方法,所以在发送通知时,也不需要去某个具体观察者的方法列表中去找对应的列表了,直接执行block中的内容就可以了。

比如上边的方法,我们就可以改成这样:


 [[NSNotificationCenter defaultCenter] addObserverForName:@"postNotification" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {

 NSLog(@"notification = %@", note.name);

 }];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"postNotification" object:nil];

这样写,可以让代码看起来更加紧凑。

而新增的queue,在默认情况下在post的线程中处理,比如这段代码:


- (void)addNotificationCenter

{    

 [[NSNotificationCenter defaultCenter] addObserverForName:@"postNotification" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {

 NSLog(@"notification = %@", note.name);

 NSLog(@"receive thread = %@", [NSThread currentThread]);

 }];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"postNotification" object:nil];

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"post thread = %@", [NSThread currentThread]);

 [[NSNotificationCenter defaultCenter] postNotificationName:@"postNotification" object:nil];

 });

}

打印出来我们就会发现:


2018-03-08 17:49:54.732746+0800 MessagePassingDemo[51217:3595209] notification = postNotification

2018-03-08 17:49:54.733093+0800 MessagePassingDemo[51217:3595209] receive thread = <NSThread: 0x60000006e780>{number = 1, name = main}

2018-03-08 17:49:54.733711+0800 MessagePassingDemo[51217:3595267] post thread = <NSThread: 0x6000004639c0>{number = 3, name = (null)}

2018-03-08 17:49:54.734052+0800 MessagePassingDemo[51217:3595267] notification = postNotification

2018-03-08 17:49:54.734320+0800 MessagePassingDemo[51217:3595267] receive thread = <NSThread: 0x6000004639c0>{number = 3, name = (null)}

除了这部分的不同之外,剩下的两者应该没有什么不同的地方了,还有注意一点就是第二种方法中的循环引用问题的发生。

实现响应方法

响应方法这边就不多说了,一种是通过调用,一种是通过block,但是两种都会传递一个NSNotification对象,注意不是NSNotificationCenter,是NSNotification

其中包括了


@property (readonly, copy) NSNotificationName name;

@property (nullable, readonly, retain) id object;

@property (nullable, readonly, copy) NSDictionary *userInfo;

一般情况下,我们可以通过userInfo来传递一些信息。

post 通知

post通知一共有三种方法。


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

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

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

同理,name和object也可以为nil,只不过发出去的消息并没有理你罢了。另外userInfo用来传递一些简单的信息。

比如:


- (void)addNotificationCenter

{

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationCall:) name:@"postNotification" object:nil];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"postNotification" object:nil userInfo:@{@"name":@"zhangsan",@"age":@"18"}];

}


- (void)notificationCall:(NSNotification *)notification

{

 NSLog(@"notification = %@", notification.name);

 NSLog(@"userinfo = %@",notification.userInfo);

}

这边就会输出:


2018-03-08 17:58:14.998128+0800 MessagePassingDemo[51452:3608470] notification = postNotification

2018-03-08 17:58:14.998407+0800 MessagePassingDemo[51452:3608470] userinfo = {

 age = 18;

 name = zhangsan;

}

移除观察者

移除观察者一共有两种方法:


- (void)removeObserver:(id)observer;

- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;

第一个方法是不针对某个特定通知,移除全部观察者,第二种是有针对性的移除某个观察者。而如果在第二种方法中name和object参数都传递nil,就和第一种方法完全一样了。

一般在dealloc中会使用第一种方法移除全部的观察者。而在viewWillDisappear中则使用第二种方式移除。

这里注意,如果我们不在合适的时机移除观察者,导致添加了重复的观察者的话,新注册的已有名字的观察者并不会覆盖之前的观察者,而是会添加两个观察者,这会导致post时响应两次或更多,比如:


- (void)addNotificationCenter

{

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationCall:) name:@"postNotification" object:nil];

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationCall:) name:@"postNotification" object:nil];

 [[NSNotificationCenter defaultCenter] postNotificationName:@"postNotification" object:nil userInfo:@{@"name":@"zhangsan",@"age":@"18"}];

}


- (void)removeNotificationCenter

{

 [[NSNotificationCenter defaultCenter] removeObserver:self];

 [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:nil];

}

打印的结果:


2018-03-08 21:27:30.566903+0800 MessagePassingDemo[52218:3651551] notification = postNotification

2018-03-08 21:27:30.567124+0800 MessagePassingDemo[52218:3651551] userinfo = {

 age = 18;

 name = zhangsan;

}

2018-03-08 21:27:30.567253+0800 MessagePassingDemo[52218:3651551] notification = postNotification

2018-03-08 21:27:30.567440+0800 MessagePassingDemo[52218:3651551] userinfo = {

 age = 18;

 name = zhangsan;

}

最后

NotificationCenter的简单使用就这么多,以上这些内容仅供个人学习使用,如果有什么不对的地方还请各位大佬多多指教。

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

推荐阅读更多精彩内容