❗️在addObserver之前如果已经有相同的通知在,需要移除,否则post后,会调用多次。
❗️不管addObserver在哪个线程执行,哪个线程执行postNotificationName哪个线程执行notificationAction,除非人为创建新的线程。但是如果创建新的线程,则notificationAction不会执行,eg:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotificationName:object:) withObject:[NSNotification notificationWithName:@"name" object:nil] waitUntilDone:YES];
});
❗️postNotificationName发出通知以后,需要等待notificationAction执行完毕才会返回(串行队列顺序执行,所以如果就是简单使用通知执行复杂任务的话,注意一下执行顺序吧!)。除非在方法中创建新的线程执行整个方法,或者使用NSNotificationQueue,但是NSNotificationQueue并不是创建子线程来执行notificationAction。
❗️相反NSNotificationQueue与线程本身没什么关系,每一个线程都只有一个NSNotificationQueue,且不能被其他线程使用。
NSNotificationQueue实际作用是:推迟通知发出,聚合通知。是根据runloop当前不同的状态和配置的NSPostingStyle来选择执行顺序。
另外,在子线程中执行enqueueNotification,notificationAction并不会被触发(NSPostNow模式除外)。换句话说就是enqueueNotification只能在主线程中使用。所以,如果执行的是耗时操作,是会卡顿的。
之所以只能在主线程使用,是因为由于触发有延迟,为了保证可以正确触发,runloop就必须一直存在着,只有主线程的runloop符合这个条件。而子线程在enqueueNotification后没有等待回调执行完毕就结束了。既然如此,只要让子线程的runloop能一直存在,那么回调也可以在子线程中执行。
NSPostingStyle有三种:
☞NSPostNow:与postNotificationName相同
☞NSPostASAP:不立即发出通知,而是在runloop匹配时调用,即:runloop处理事件源时
☞NSPostWhenIdle:runloop闲置的时候post,即:runloop进入睡眠时
[[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:@"name" object:nil] postingStyle:2 coalesceMask:NSNotificationNoCoalescing forModes:@[NSDefaultRunLoopMode]];
❗️两种添加通知的方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationAction:) name:@"name" object:nil];
id observe = [[NSNotificationCenter defaultCenter] addObserverForName:@"name" object:nil queue:[NSOperationQueue new] usingBlock:^(NSNotification * _Nonnull note) {
}];
第一种方法在iOS9.0后自动释放,不需要removeObserver。第二种方法需要创建id对象observe,最后释放observe。
第一种方法NSNotificationCenter弱引用接收通知的对象,postNotificationName方法里面让此对象执行相应的方法(invoke)。因为是弱引用,所以一旦此对象销毁,就不需要NSNotificationCenter再销毁。
而第二种方法则是创建了一个强引用的对象(就跟第一种创建方法的self一样)来保存通知的属性,包括名称、线程、回调方法。在postNotificationName方法里面调用此对象,然后在对应的线程中执行回调方法。在removeObserver方法里面将此对象释放。因为是强引用,所以需要调用removeObserver来通知NSNotificationCenter去销毁。
❗️通知合并:NSNotificationCoalescing,保证在runloop符合条件的情况下只执行一次
参考:
//www.greatytc.com/p/86e1d721c6b1
https://www.mikeash.com/pyblog/friday-qa-2010-01-08-nsnotificationqueue.html