iOS中通知非同步?同步?

b10l07發表於2017-08-07

讓人很納悶的一個問題:通知是同步的還是非同步的

在iOS開發中有人問“通知是同步的還是非同步的”。個人感覺問的這個問題本身就有問題,你只能說通知的執行方法是同步的還是非同步的,或者說傳送通知是同步的還是非同步的...對於通知是同步還是非同步,這個問法本身就很籠統,讓人不明白你是要問什麼,所以很納悶。

一個通知的小例子

這裡我們用一個簡單的小例子來看看通知的執行是在子執行緒還是在主執行緒。

1、 首先我們在viewDidLoad方法裡面註冊了一個通知:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(test) name:kTestNotificationName object:nil];
}

通知的註冊者是self,執行方法是test,name是一個字元常量

static NSString *kTestNotificationName = @"TestNotification";

2、我們是在ViewController中測試的,借用touch方法來試試

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    dispatch_queue_t queue = dispatch_queue_create("CONCURRENT QUEUE", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
       
        [[NSNotificationCenter defaultCenter] postNotificationName:kTestNotificationName object:nil];
        
        NSLog(@"%@",[NSThread currentThread]);
    });
}

這裡我們先寫了一個佇列CONCURRENT QUEUE,然後執行非同步任務。非同步任務裡面我們傳送通知。

3、test方法裡列印

- (void)test {
    NSLog(@"test %@",[NSThread currentThread]);
}

4、列印結果

2017-08-07 16:55:16.987 Test[4333:191487] test <NSThread: 0x608000266e00>{number = 3, name = (null)}
2017-08-07 16:55:16.987 Test[4333:191487] <NSThread: 0x608000266e00>{number = 3, name = (null)}
  • 列印結果顯示我們是在子執行緒中傳送的通知,則通知的執行方法也在子執行緒中執行。
  • 如果將上述執行緒改成主執行緒中傳送通知的話,通知執行方法就會在主執行緒中執行,主執行緒中列印結果如下:
2017-08-07 17:16:08.164 Test[4472:200122] test <NSThread: 0x60000007d6c0>{number = 1, name = main}
2017-08-07 17:16:08.165 Test[4472:200122] <NSThread: 0x60000007d6c0>{number = 1, name = main}

完整例子如下:

#import "ViewController.h"

static NSString *kTestNotificationName = @"TestNotification";

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //註冊,主執行緒
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(test) name:kTestNotificationName object:nil];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //建立佇列
    dispatch_queue_t queue = dispatch_queue_create("CONCURRENT QUEUE", DISPATCH_QUEUE_CONCURRENT);
    //執行非同步任務
    dispatch_sync(queue, ^{
        
        [[NSNotificationCenter defaultCenter] postNotificationName:kTestNotificationName object:nil];
        
        NSLog(@"%@",[NSThread currentThread]);
    });
}

- (void)test {
    NSLog(@"test %@",[NSThread currentThread]);
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kTestNotificationName object:nil];
}
@end

例子中測試子執行緒中傳送通知,看通知方法是在哪個執行緒中執行;我們可以將非同步任務改成同步任務,看看在主執行緒中傳送通知,確認一下執行方法是在主執行緒。

總結

  • 傳送通知是在哪個執行緒,則執行通知的方法就在哪個執行緒中執行。

  • 對於有些人說“通知都是非同步的”,我想了想可能這指的是通知傳送後找註冊者的這個過程是非同步的吧?是不是這樣呢?

相關文章