先來看看官方的文檔,是這樣寫的:
In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself.
翻譯過來是:
在多線程應用中,Notification在哪個線程中post,就在哪個線程中被轉發,而不一定是在注冊觀察者的那個線程中。
也就是說,Notification的發送與接收處理都是在同一個線程中。為了說明這一點,我們先來看一個示例:
代碼清單1:Notification的發送與處理
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"current thread = %@", [NSThread currentThread]);
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:TEST_NOTIFICATION object:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil userInfo:nil];
});
}
- (void)handleNotification:(NSNotification *)notification
{
NSLog(@"current thread = %@", [NSThread currentThread]);
NSLog(@"test notification");
}
@end
其輸出結果如下:
2015-03-11 22:05:12.856 test[865:45102] current thread = {number = 1, name = main}
2015-03-11 22:05:12.857 test[865:45174] current thread = {number = 2, name = (null)}
2015-03-11 22:05:12.857 test[865:45174] test notification
可以看到,雖然我們在主線程中注冊了通知的觀察者,但在全局隊列中post的Notification,并不是在主線程處理的。所以,這時候就需要注意,如果我們想在回調中處理與UI相關的操作,需要確保是在主線程中執行回調。
這時,就有一個問題了,如果我們的Notification是在二級線程中post的,如何能在主線程中對這個Notification進行處理呢?或者換個提法,如果我們希望一個Notification的post線程與轉發線程不是同一個線程,應該怎么辦呢?我們看看官方文檔是怎么說的:
For example, if an object running in a background thread is listening for notifications from the user interface, such as a window closing, you would like to receive the notifications in the background thread instead of the main thread. In these cases, you must capture the notifications as they are delivered on the default thread and redirect them to the appropriate thread.
這里講到了“重定向”,就是我們在Notification所在的默認線程中捕獲這些分發的通知,然后將其重定向到指定的線程中。
一種重定向的實現思路是自定義一個通知隊列(注意,不是NSNotificationQueue對象,而是一個數組),讓這個隊列去維護那些我們需要重定向的Notification。我們仍然是像平常一樣去注冊一個通知的觀察者,當Notification來了時,先看看post這個Notification的線程是不是我們所期望的線程,如果不是,則將這個Notification存儲到我們的隊列中,并發送一個信號(signal)到期望的線程中,來告訴這個線程需要處理一個Notification。指定的線程在收到信號后,將Notification從隊列中移除,并進行處理。
官方文檔已經給出了示例代碼,在此借用一下,以測試實際結果:
新聞熱點
疑難解答