之前面试被问到NSNotification在发送通知的时候,是同步还是异步,当时自己真不清楚,然后这两天又遇到这个问题,自己写了代码测试一下。
代码如下:
#import "ViewController.h"
#define kNotificationName @"kNotificationName"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化一个按钮
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 50)];
button.backgroundColor = [UIColor orangeColor];
[button setTitle:@"触发通知" forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonDown) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
// 注册通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(actionNotification:)
name:kNotificationName
object:nil];
}
- (void) actionNotification: (NSNotification*)notification
{
NSString* message = notification.object;
NSLog(@"%@",message);
sleep(3);
NSLog(@"通知说话结束");
}
- (void)buttonDown
{
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationName object:@"通知说话开始"];
NSLog(@"按钮说话");
}
@end
点击按钮后,打印结果如下:
通过这里的时间间隔可以看出,在抛出通知以后,观察者在通知事件处理完成以后(这里我们休眠3秒),抛出者才会往下继续执行,也就是说这个过程默认是同步的;当发送通知时,通知中心会一直等待所有的observer都收到并且处理了通知才会返回到poster;
网上找了下,如果我们想改同步为异步,也是有办法的。
办法1:
让通知事件处理方法在子线程中执行,例如:
#import "ViewController.h"
#define kNotificationName @"kNotificationName"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化一个按钮
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 50)];
button.backgroundColor = [UIColor orangeColor];
[button setTitle:@"触发通知" forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonDown) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
// 注册通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(actionNotification:)
name:kNotificationName
object:nil];
}
- (void) actionNotification: (NSNotification*)notification
{
// NSString* message = notification.object;
// NSLog(@"%@",message);
//
// sleep(3);
//
// NSLog(@"通知说话结束");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString* message = notification.object;
NSLog(@"%@",message);
sleep(3);
NSLog(@"通知说话结束:%@",[NSThread currentThread]);
});
}
- (void)buttonDown
{
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationName object:@"通知说话开始"];
// NSLog(@"按钮说话");
NSLog(@"按钮说话:%@",[NSThread currentThread]);
}
@end
点击按钮后,打印结果如下:
办法2:
可以通过NSNotificationQueue的enqueueNotification: postingStyle:和enqueueNotification: postingStyle: coalesceMask: forModes: 方法将通告放入队列,实现异步发送,在把通告放入队列之后,这些方法会立即将控制权返回给调用对象。
我们修改按钮事件如下:
- (void)buttonDown
{
NSNotification *notification = [NSNotification notificationWithName:kNotificationName
object:@"通知说话开始"];
[[NSNotificationQueue defaultQueue] enqueueNotification:notification
postingStyle:NSPostASAP];
// [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationName object:@"通知说话开始"];
NSLog(@"按钮说话");
}
点击按钮后,打印结果如下: