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. 每條線程都有一個默認的通知隊列熄云, 隊列的任務(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)系作者
  • 序言:七十年代末歌懒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子溯壶,更是在濱河造成了極大的恐慌及皂,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件且改,死亡現(xiàn)場離奇詭異验烧,居然都是意外死亡,警方通過查閱死者的電腦和手機又跛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門碍拆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人慨蓝,你說我怎么就攤上這事感混。” “怎么了礼烈?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵弧满,是天一觀的道長。 經(jīng)常有香客問我此熬,道長庭呜,這世上最難降的妖魔是什么滑进? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮募谎,結(jié)果婚禮上扶关,老公的妹妹穿的比我還像新娘。我一直安慰自己近哟,他們只是感情好驮审,可當(dāng)我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吉执,像睡著了一般疯淫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上戳玫,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天熙掺,我揣著相機與錄音,去河邊找鬼咕宿。 笑死币绩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的府阀。 我是一名探鬼主播缆镣,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼试浙!你這毒婦竟也來了董瞻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤田巴,失蹤者是張志新(化名)和其女友劉穎钠糊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體壹哺,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡抄伍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了管宵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片截珍。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖箩朴,靈堂內(nèi)的尸體忽然破棺而出笛臣,到底是詐尸還是另有隱情,我是刑警寧澤隧饼,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布沈堡,位于F島的核電站,受9級特大地震影響燕雁,放射性物質(zhì)發(fā)生泄漏诞丽。R本人自食惡果不足惜鲸拥,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望僧免。 院中可真熱鬧刑赶,春花似錦、人聲如沸懂衩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浊洞。三九已至牵敷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間法希,已是汗流浹背枷餐。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留苫亦,地道東北人毛肋。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像屋剑,于是被迫代替她去往敵國和親润匙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容