1. 程式人生 > >ios-通知中心原理

ios-通知中心原理

關於通知中心,我們應該都去發過通知以及去監聽這個通知,我們下面就做一個簡單的探析。

首先我們可以先通過打斷點的方式去

po [NSNotificationCenter defaultCenter]

去檢視它的資訊,我們會發現有很多系統的通知在裡面,在裡面我們可以找到我們釋出的通知。下面的object就是指定接收哪個物件發出的通知。

 [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(dealThings) name:@"ZXDealThings" object:nil];


我們如果實現了下面這兩個方法實現點選螢幕去傳送通知,這樣的話是先去執行輸出1的語句,然後傳送通知,下面的dealThings方法先把方法處理完成之後才會再反回去執行輸出3這條語句。也就是說是同步執行的。

通知中心預設是以同步的方式傳送通知的,也就是說,當一個物件傳送了一個通知,只有當該通知的所有接受者都接受到了通知中心分發的通知訊息並且處理完成後,傳送通知的物件才能繼續執行接下來的方法

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"1");
    
    [[NSNotificationCenter defaultCenter]postNotificationName:@"ZXDealThings" object:nil];
    
    NSLog(@"3");
}

-(void)dealThings
{
    
    NSLog(@"處理訊息---%@",[NSThread currentThread]);
}

我們如果想要實現不去管下面的處理方法是否完成就去執行NSLog(@"3")這條語句的話,我們可以這麼做。
    NSNotification * notification = [NSNotification notificationWithName:@"ZXDealThings" object:nil];
      
    //獲取當前執行緒下的通知佇列,每個執行緒有一個預設的通知佇列
    NSNotificationQueue * notificationQueue = [NSNotificationQueue defaultQueue];
    
    NSLog(@"1");
    [notificationQueue enqueueNotification:notification postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing 
     forModes:@[NSRunLoopCommonModes]];
    NSLog(@"3");

這裡的enqueueNotification第一個引數就是要傳送的通知。

第二個引數就是傳送通知的型別有三個型別

    NSPostWhenIdle = 1,空閒時傳送
    NSPostASAP = 2, 儘快傳送
    NSPostNow = 3 立即傳送
第三個引數就是合併的規則,如果是同步的,合併是沒有效果的。
    NSNotificationNoCoalescing = 0,不合並
    NSNotificationCoalescingOnName = 1,按通知的名字合併,也就是說名字相同的通知會被合併,但是如果我們coalesceMask:設定的不一樣即使名字一樣也會發兩次
    NSNotificationCoalescingOnSender = 2 按通知的傳送者合併
第四個引數就是執行迴圈執行的模式

當我們如果是在子執行緒當中執行上面的那段程式碼,並且postingStyle還是設定的NSPostWhenIdle,處理通知的方法啊並沒有執行.可能就是因為子執行緒已經銷燬了,因為它在等執行迴圈空閒的時刻。我們其實可以開啟子執行緒的執行迴圈讓子執行緒不銷燬,要想開啟子執行緒的執行迴圈並且不結束,我們就需要去新增一個資源。

在子執行緒中呼叫的方法中加上這麼幾句話就可以了,下面是新增一個基於埠的輸入源

     NSPort * port = [NSPort new];
    [[NSRunLoop currentRunLoop]addPort:port forMode:NSRunLoopCommonModes];
    [[NSRunLoop currentRunLoop]run];
    

如果我們將NSPostWhenIdle改成NSPostNow的話就可以進行收到通知的處理並且是同步的。

當我們連續呼叫了view的setNeedsDisplay方法的時候,系統會幫我們做一個合併操作,只會呼叫一次drawRect方法,這個也是非同步執行的。並不會馬上執行drawRect方法

    [self.blueView setNeedsDisplay];
    [self.blueView setNeedsDisplay];
    [self.blueView setNeedsDisplay];
    [self.blueView setNeedsDisplay];
    [self.blueView setNeedsDisplay];


我們在底層當中的訊息的觸發其實是依賴與埠的,我們想要在一個執行緒中發訊息,在另一個執行緒中進行處理的話,我們可以用埠來實現,程式碼如下

@interface ViewController ()<NSPortDelegate>
{
    NSPort *_port;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _port = [NSPort new];
    _port.delegate = self;
    
    //把埠加在哪個執行緒裡面就在哪個執行緒處理
    [[NSRunLoop currentRunLoop]addPort:_port forMode:NSRunLoopCommonModes];
    
    
}
//傳送訊息
-(void)sendPort
{
    NSLog(@"傳送訊息 %@",[NSThread currentThread]);
    [_port sendBeforeDate:[NSDate date] msgid:1000 components:nil from:nil reserved:0];
    NSLog(@"傳送結束");
}
//處理訊息
-(void)handlePortMessage:(NSPortMessage *)message
{
    
    NSLog(@"處理任務:%@",[NSThread currentThread]);
    NSObject * obj = (NSObject *)message;
    NSLog(@"%@",[obj valueForKey:@"msgid"]);
    
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [NSThread detachNewThreadSelector:@selector(sendPort) toTarget:self withObject:nil];
   
 
}