NSNotification重定向

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**
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,558評論 25 708
  • 史上最全的iOS面試題及答案 iOS面試小貼士———————————————回答好下面的足夠了----------...
    Style_偉閱讀 2,446評論 0 35
  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛閱讀 2,014評論 0 7
  • 多線程、特別是NSOperation 和 GCD 的內部原理。運行時機制的原理和運用場景。SDWebImage的原...
    LZM輪回閱讀 2,043評論 0 12
  • __block和__weak修飾符的區別其實是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,375評論 0 6