iOS NotificationCenter 總結(jié)

參考文檔: Notification Programming Topics

NSNotificationCenter

  1. 用于單個進程內(nèi)的通知發(fā)送
  2. postNotificationName:object:postNotificationName:object:userInfo: 的調(diào)用為同步方式,該方法會等待通知被發(fā)送和處理后返回。
  3. 通知注冊的handler是在發(fā)送通知的線程中被調(diào)用,主線程注冊了通知,子線程發(fā)送了通知,通知的處理就是在子線程中。如果想在主線程中同步處理該通知,可以通過mach port, 將通知轉(zhuǎn)發(fā)給主線程。

NSNotificationQueue

NSNotificationQueue objects, or simply, notification queues, act as buffers for notification centers (instances of NSNotificationCenter). The NSNotificationQueue class contributes two important features to the Foundation Kit’s notification mechanism: the coalescing of notifications and asynchronous posting.

Using the NSNotificationCenter’s postNotification: method and its variants, you can post a notification to a notification center. However, the invocation of the method is synchronous: before the posting object can resume its thread of execution, it must wait until the notification center dispatches the notification to all observers and returns. A notification queue, on the other hand, maintains notifications (instances of NSNotification) generally in a First In First Out (FIFO) order. When a notification rises to the front of the queue, the queue posts it to the notification center, which in turn dispatches the notification to all objects registered as observers.

Every thread has a default notification queue, which is associated with the default notification center for the process. You can create your own notification queues and have multiple queues per center and thread.

  1. 每條線程都有一個默認(rèn)的通知隊列, 隊列的任務(wù)先入先出
  2. 通過通知隊列可以異步發(fā)送通知,通過 NSNotificationCenter 只能同步發(fā)送通知
  3. 通知隊列允許通知折疊,多條通知折疊為一條發(fā)送,可以指定折疊的策略, 例如: 按通知名字折疊
  4. 需要關(guān)聯(lián)runloop,指定要運行的runloop mode
  5. 因為指定了runloop,指定通知發(fā)送的時機
    • NSPostASAP
    • NSPostWhenIdle
    • NSPostNow

調(diào)用:

NSNotificationQueue *queue = [NSNotificationQueue defaultQueue];
[queue enqueueNotification ...]

NSDistributedNotificationCenter

Each process has a default distributed notification center that you access with the NSDistributedNotificationCenter +defaultCenter class method. This distributed notification center handles notifications that can be sent between processes on a single machine. For communication between processes on different machines, use distributed objects (see Distributed Objects Programming Topics).

Posting a distributed notification is an expensive operation. The notification gets sent to a systemwide server that then distributes it to all the processes that have objects registered for distributed notifications. The latency between posting the notification and the notification’s arrival in another process is unbounded. In fact, if too many notifications are being posted and the server’s queue fills up, notifications can be dropped.

Distributed notifications are delivered via a process’s run loop. A process must be running a run loop in one of the “common” modes, such as NSDefaultRunLoopMode, to receive a distributed notification. If the receiving process is multithreaded, do not depend on the notification arriving on the main thread. The notification is usually delivered to the main thread’s run loop, but other threads could also receive the notification.

Whereas a regular notification center allows any object to be observed, a distributed notification center is restricted to observing a string object. Because the posting object and the observer may be in different processes, notifications cannot contain pointers to arbitrary objects. Therefore, a distributed notification center requires notifications to use a string as the notification object. Notification matching is done based on this string, rather than an object pointer.

  1. 提供跨進程通知的能力, iOS用不了, iOS需要使用CFNotificationCenterGetDarwinNotifyCenter
  2. 當(dāng)通知隊列滿的時候,后面到來的通知會被丟棄
  3. 需要關(guān)聯(lián)runloop, 一般的通知會發(fā)布到主線程中,但是子線程也可以收到通知
  4. 通知的object信息,只能是string, 因為跨進程通知,傳遞對象指針沒有意義
  5. 可以定制策略和發(fā)送時機
- (void)addObserver:(id)observer selector:(SEL)selector name:(NSNotificationName)name object:(NSString *)object suspensionBehavior:(NSNotificationSuspensionBehavior)suspensionBehavior;

- (void)postNotificationName:(NSNotificationName)name object:(NSString *)object userInfo:(NSDictionary *)userInfo options:(NSDistributedNotificationOptions)options;

CFNotificationCenterGetDarwinNotifyCenter

支持 iOS、macOS, 提供跨進程通知的能力

swift 中如何使用, 參考: Swift - 正確使用CFNotificationCenterAddObserver 回調(diào)

//發(fā)送通知
sendNotificationForMessageWithIdentifier(identifier: "broadcastStarted")
func sendNotificationForMessageWithIdentifier(identifier : String) {
    let center : CFNotificationCenter = CFNotificationCenterGetDarwinNotifyCenter()
    let identifierRef : CFNotificationName = CFNotificationName(identifier as CFString)
    CFNotificationCenterPostNotification(center, identifierRef, nil, nil, true)
}

///通知回調(diào)
func callback(_ name : String) {
    print("received notification: \(name)")
}

///通知注冊
func registerObserver() {
    let observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer, { (_, observer, name, _, _) -> Void in
        if let observer = observer, let name = name {
            // Extract pointer to `self` from void pointer:
            let mySelf = Unmanaged<OTCAppealVC>.fromOpaque(observer).takeUnretainedValue()
            // Call instance method:
            mySelf.callback(name.rawValue as String)
        }
    }, "broadcastFinished" as CFString, nil,.deliverImmediately)
}

//通知移除
deinit {
    let observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())
    let cfName: CFNotificationName = CFNotificationName("broadcastFinished" as CFString)
    CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer, cfName, nil)
}

NSMachPort 轉(zhuǎn)發(fā)通知到特定線程

例如在主線程監(jiān)聽,在子線程中發(fā)送通知,希望通知仍然在主線程中處理

#import "ViewController.h"

@interface ViewController ()<NSMachPortDelegate>
@property(nonatomic, strong) NSMutableArray *notifications;
@property (nonatomic, strong) NSThread *notificationThread;
@property (nonatomic, strong) NSLock *notificationLock;
@property (nonatomic, strong) NSMachPort *notificationPort;
@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.notifications = [[NSMutableArray alloc] init];
    self.notificationThread = [NSThread mainThread];
    self.notificationLock = [[NSLock alloc] init];
    self.notificationPort = [[NSMachPort alloc] init];
    
    [self.notificationPort setDelegate:self];
    [[NSRunLoop currentRunLoop] addPort:self.notificationPort
            forMode:NSRunLoopCommonModes];
    
    [[NSNotificationCenter defaultCenter]
            addObserver:self
            selector:@selector(processNotification:)
            name:@"NotificationName"
            object:nil];
    
    
    for (int i = 0; i< 10; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationName" object:self];
        });
    }
}

- (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] != self.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];

        NSLog(@"notification receive in thread: %@", [NSThread currentThread]);
    }
    else {
        // Process the notification here;
        NSLog(@"notification handle in thread: %@", [NSThread currentThread]);
    }
}

@end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容