iOS高级面试之NSNotificationCenter是同步操作还是异步操作

转载:http://blog.csdn.net/u014220518/article/details/70598063

http://blog.csdn.net/intheair100/article/details/46422435

前言

最近有个小伙伴到喜马拉雅去面试,面试官问他一个问题就是“通知中心是同步操作还是异步操作?”,小伙伴回答成异步了,然后就是回家等消息,然后就是没有然后了。。。

我先举几个小的列子给大家瞅瞅:

发送通知

  1. - (void)sentValueBtnClick:(UIButton *)button{  
  2.     NSLog(@"发送通知");  
  3.     NSDictionary *dict = @{@"myValue":@"ZFJ通知传值"};  
  4.     [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"KPassValue" object:nil userInfo:dict]];  
  5. }  

接收通知

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.     // Do any additional setup after loading the view, typically from a nib.  
  4.     _textField.layer.borderColor = [UIColor redColor].CGColor;  
  5.     _textField.layer.borderWidth = 1.0;  
  6.       
  7.     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(passValue:) name:@"KPassValue" object:nil];  
  8. }  
  9.   
  10. - (void)passValue:(NSNotification *)text{  
  11.     NSString *valueStr = text.userInfo[@"myValue"];  
  12.     NSLog(@"收到值:%@",valueStr);  
  13.     sleep(3);  
  14.     self.textField.text = valueStr;  
  15.     NSLog(@"通知赋值完毕");  
  16. }  

打印结果:

2017-04-24 14:36:42.043 NSNotification[8150:145628] 发送通知

2017-04-24 14:36:42.043 NSNotification[8150:145628] 收到值:ZFJ通知传值

2017-04-24 14:36:45.044 NSNotification[8150:145628] 通知赋值完毕


案例分析

通过打印我们可以看出,当我们发送通知以后,观察者在接收到值以后,我们休眠3秒,程序才会继续往下执行,也就是说这个过程是同步的;我认为这里面设计为同步,是考虑到这一点,那就是一个通知可能有多个监听者,采用同步的方式能够保证所有的观察者都能够对通知做出相应,不会遗漏。

异步操作

如果我们想异步操作怎么办呢?莫急且看下面:

发送通知:

  1. - (void)sentValueBtnClick:(UIButton *)button{  
  2.     NSLog(@"发送通知");  
  3.     NSDictionary *dict = @{@"myValue":@"ZFJ通知传值"};  
  4.     dispatch_async(dispatch_get_global_queue(00), ^{  
  5.         [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"KPassValue" object:nil userInfo:dict]];  
  6.     });  
  7. }  

接受通知:

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.     // Do any additional setup after loading the view, typically from a nib.  
  4.     _textField.layer.borderColor = [UIColor redColor].CGColor;  
  5.     _textField.layer.borderWidth = 1.0;  
  6.       
  7.     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(passValue:) name:@"KPassValue" object:nil];  
  8. }  
  9.   
  10. - (void)passValue:(NSNotification *)text{  
  11.     NSString *valueStr = text.userInfo[@"myValue"];  
  12.     NSLog(@"收到值:%@",valueStr);  
  13.     dispatch_async(dispatch_get_global_queue(00), ^{  
  14.         sleep(3);  
  15.         self.textField.text = valueStr;  
  16.         NSLog(@"通知赋值完毕");  
  17.     });  
  18. }  

与javascript中的事件机制不同,ios里的事件广播机制是同步的,默认情况下,广播一个通知,会阻塞后面的代码:

Objc代码  收藏代码
  1. -(void) clicked  
  2. {  
  3.     NSNotificationCenter *center =  [NSNotificationCenter defaultCenter];  
  4.     [center postNotificationName:@"event_happend" object:self];  
  5.       
  6.     NSLog(@"all handler done");  
  7. }  


按下按钮后,发送一个广播,此前已经注册了2个此事件的侦听者

Objc代码  收藏代码
  1. -(id) init  
  2. {  
  3.     self = [super init];  
  4.     if(self){  
  5.         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(whenReceive:) name:@"event_happend" object:nil];  
  6.     }  
  7.     return self;  
  8. }  
  9.   
  10.   
  11. -(void) whenReceive:(NSNotification*) notification  
  12. {  
  13.     NSLog(@"im1111");  
  14. }  

Objc代码  收藏代码
  1. -(id) init  
  2. {  
  3.     self = [super init];  
  4.     if(self){  
  5.         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(whenReceive:) name:@"event_happend" object:nil];  
  6.     }  
  7.     return self;  
  8. }  
  9.   
  10.   
  11. -(void) whenReceive:(NSNotification*) notification  
  12. {  
  13.     NSLog(@"im22222");  
  14. }  

执行这段代码,首先会输出im1111,然后是im22222,最后才是all handler done。调试发现,代码始终是跑在同一个线程中(广播事件的线程),广播事件之后的代码被阻塞,直到所有的侦听者都执行完响应

所以,由于NotificationCenter的这个特性,如果希望广播的事件异步处理,则需要在侦听者的方法里开启新线程。应该把Notification作为组件间解耦的方式,而不是利用它来实现异步处理。


与javascript中的事件机制不同,ios里的事件广播机制是同步的,默认情况下,广播一个通知,会阻塞后面的代码:

Objc代码  收藏代码
  1. -(void) clicked  
  2. {  
  3.     NSNotificationCenter *center =  [NSNotificationCenter defaultCenter];  
  4.     [center postNotificationName:@"event_happend" object:self];  
  5.       
  6.     NSLog(@"all handler done");  
  7. }  


按下按钮后,发送一个广播,此前已经注册了2个此事件的侦听者

Objc代码  收藏代码
  1. -(id) init  
  2. {  
  3.     self = [super init];  
  4.     if(self){  
  5.         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(whenReceive:) name:@"event_happend" object:nil];  
  6.     }  
  7.     return self;  
  8. }  
  9.   
  10.   
  11. -(void) whenReceive:(NSNotification*) notification  
  12. {  
  13.     NSLog(@"im1111");  
  14. }  

Objc代码  收藏代码
  1. -(id) init  
  2. {  
  3.     self = [super init];  
  4.     if(self){  
  5.         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(whenReceive:) name:@"event_happend" object:nil];  
  6.     }  
  7.     return self;  
  8. }  
  9.   
  10.   
  11. -(void) whenReceive:(NSNotification*) notification  
  12. {  
  13.     NSLog(@"im22222");  
  14. }  

执行这段代码,首先会输出im1111,然后是im22222,最后才是all handler done。调试发现,代码始终是跑在同一个线程中(广播事件的线程),广播事件之后的代码被阻塞,直到所有的侦听者都执行完响应

所以,由于NotificationCenter的这个特性,如果希望广播的事件异步处理,则需要在侦听者的方法里开启新线程。应该把Notification作为组件间解耦的方式,而不是利用它来实现异步处理。

猜你喜欢

转载自blog.csdn.net/shifang07/article/details/79129404
今日推荐