Notification的發送與接收處理都是在同一個線程中,如果我們希望一個Notification的post線程與轉發線程不是同一個線程的話就要對通知進行重定向,“重定向”就是我們在Notification所在的默認線程中捕獲這些分發的通知,然后將其重定向到指定的線程中
一種重定向的實現思路是自定義一個通知隊列(注意,不是NSNotificationQueue對象,而是一個數組),讓這個隊列去維護那些我們需要重定向的Notification。我們仍然是像平常一樣去注冊一個通知的觀察者,當Notification來了時,先看看post這個Notification的線程是不是我們所期望的線程,如果不是,則將這個Notification存儲到我們的隊列中,并發送一個信號(signal)到期望的線程中,來告訴這個線程需要處理一個Notification。指定的線程在收到信號后,將Notification從隊列中移除,并進行處理。官方代碼如下:#####
@interface ViewController ()
@property (nonatomic) NSMutableArray *notifications; // 通知隊列
@property (nonatomic) NSThread *notificationThread; // 期望線程
@property (nonatomic) NSLock *notificationLock; // 用于對通知隊列加鎖的鎖對象,避免線程沖突
@property (nonatomic) NSMachPort *notificationPort; // 用于向期望線程發送信號的通信端口
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"current thread = %@", [NSThread currentThread]);
// 初始化
self.notifications = [[NSMutableArray alloc] init];
self.notificationLock = [[NSLock alloc] init];
self.notificationThread = [NSThread currentThread];
self.notificationPort = [[NSMachPort alloc] init];
self.notificationPort.delegate = self;
// 往當前線程的run loop添加端口源
// 當Mach消息到達而接收線程的run loop沒有運行時,則內核會保存這條消息,直到下一次進入run loop
[[NSRunLoop currentRunLoop] addPort:self.notificationPort
forMode:(__bridge NSString *)kCFRunLoopCommonModes];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processNotification:) name:@"TestNotification" object:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil userInfo:nil];
});
}
- (void)handleMachMessage:(void *)msg {
[self.notificationLock lock];
**while** ([self.notifications count]) {
NSNotification *notification = [self.notifications objectAtIndex:0];
[self.notifications removeObjectAtIndex:0];
[self.notificationLock unlock];
[self processNotification:notification];
[self.notificationLock lock];
};
[self.notificationLock unlock];
}
- (void)processNotification:(NSNotification *)notification {
if ([NSThread currentThread] != _notificationThread) {
// Forward the notification to the correct thread.
[self.notificationLock lock];
[self.notifications addObject:notification];
[self.notificationLock unlock];
[self.notificationPort sendBeforeDate:[NSDate date]
components:nil
from:nil
reserved:0];
}
else {
// Process the notification here;
NSLog(@"current thread = %@", [NSThread currentThread]);
NSLog(@"process notification");
}
}
@end
運行后,其輸出如下:
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #ffffff}span.s1 {font-variant-ligatures: no-common-ligatures}
**current thread = <NSThread: 0x7fc8f9f003f0>{number = 1, name = main}**
**current thread =<NSThread: 0x7fc8f9f003f0>{number = 1, name = main}**
**process notification**