NSNotification 平时用的还是比较多的。我们知道通知是同步的,并且通知的处理是与发送处于一个线程中。这就引发了一个问题,通知和线程的关系?
NSNotification 与线程之间的关系
1.开启一个线程发送一个通知
...
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNoti) name:@"customNotification" object:nil];
[NSThread detachNewThreadSelector:@selector(sendNoti) toTarget:self withObject:nil];
}
...
- (void)sendNoti{
NSLog(@"%@", [NSThread currentThread]);
[[NSNotificationCenter defaultCenter] postNotificationName:@"customNotification" object:nil];
}
- (void)handleNoti
{
NSLog(@"%@", [NSThread currentThread]);
}
通过log日志可以看出都是在同一个线程中执行的。但是并不能解决问题
NSNotificationQueue
在 NSNotificationQueue 的文档介绍中有这么一句话
Every thread has a default notification queue, which is associated with the default notification center for the task. You can create your own notification queues and have multiple queues per center and thread.
大体意思就是说每个线程有一个或多个通知队列,所以通知是依赖于线程。
NSNotificationQueue 和线程是有关系的,那么现在问题是通知队列如何加载通知,通过文档可以得到一个方法,将通知加入队列。
typedef NS_OPTIONS(NSUInteger, NSNotificationCoalescing) {
NSNotificationNoCoalescing = 0,
NSNotificationCoalescingOnName = 1,
NSNotificationCoalescingOnSender = 2
};
typedef NS_ENUM(NSUInteger, NSPostingStyle) {
NSPostWhenIdle = 1, /// 空闲时发送
NSPostASAP = 2, /// 尽快发送
NSPostNow = 3 /// 现在发送
};
/**
* postingStyle: 发送通知的时机
* coalesceMask: 消息合并
* modes : runloop 运行状态
**/
- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle coalesceMask:(NSNotificationCoalescing)coalesceMask forModes:(nullable NSArray<NSRunLoopMode> *)modes;
通过 NSNotificationQueue 来发送
- (void)sendNoti{
NSNotification *noti = [NSNotification notificationWithName:@"customNotification" object:nil];
NSNotificationQueue *queue = [NSNotificationQueue defaultQueue];
[queue enqueueNotification:noti postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing forModes:nil];
}
这个时候可以看下打印数据,通知的处理并未执行。由于我设置的执行时机是在当前线程空闲时机,所以,在非主线程的情况下,线程执行完毕会自动销毁,所以,也就不能执行。这个时候可以修改 postingStyle 为 NSPostNow。这就能能够正常执行。(由于runloop的关系,主线程是不会被销毁的,所以不会存在这个问题)
总结:主要还是文档中的那句话,一个线程默认会有一个通知队列。线程销毁,通知也就结束。通知为先进先出,交于 NSNotificationCenter 去执行。
NSNotification如何实现异步
虽然可以通过修改 postingStyle ,让通知在空闲的时候执行,但是由于还是处于当前线程中,只能算是“伪异步”。就通知本身而言,是不能实现同步的。有文章说可以使用 NSPort 进行端口通信,来实现通知的“异步”。虽然形式上发送和处理消息可以指定线程。但本身已不是通知功能,只能说是自定义一个通知吧~
网友评论