【API使用系列】Notification消息通知專題

1 NSNotificationCenter機制

1.1 原理

1.1.1 不移除通知掛機原因分析

@implementation MRCObject

- (id)init

{

    if (self = [super init]) {

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

    }

    return self;

}


- (void)test

{

    NSLog(@"=================");

}


- (void)dealloc

{

    [super dealloc];

}


@end



在另一個類中引用:

- (void)viewDidLoad {

    [superview DidLoad];

    MRCObject *obj = [[MRCObjectalloc] init];

    [obj release];

    [[NSNotificationCenter defaultCenter] postNotificationName: @"test" object: nil];

}


    在進入這個vc後,我們發現掛了。。

    我們可以發現,向野指針對象發送了消息,所以掛掉了。從這點來看,蘋果實現也基本差不多是這樣的,只保存了個對象的地址,並沒有在銷燬的時候置爲nil。

    這點就可以證明,addObserver後,必須要有remove操作。


1.1.2 ViewController中不手動移除通知不掛機原因分析

    現在我們在UIViewController中註冊通知,不移除,看看會不會掛掉。

- (void)viewDidLoad {

    [superviewDidLoad];

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

}

    首先用navigationController進入到這個頁面,然後pop出去。最後點擊發送通知的按鈕事件:

- (void)didButtonClicked:(id)sender

{

    [[NSNotificationCenter defaultCenter] postNotificationName: @"test" object: nil];

}

        無論你怎麼點擊這個按鈕,他就是不掛!這下,是不是很鬱悶了?我們可以找找看,你代碼裏面沒有remove操作,但是NSNotificationCenter那邊已經移除了,不然肯定會出現上面野指針的問題。看來看去,也只能說明是UIViewController自己銷燬的時候幫我們暗地裏移除了。

        那我們如何證明呢?由於我們看不到源碼,所以也不知道有沒有調用。這個時候,我們可以從這個通知中心下手!!!怎麼下手呢?我只要證明UIViewController在銷燬的時候調用了remove方法,就可以證明我們的猜想是對的了!這個時候,就需要用到我們強大的類別這個特性了。我們爲NSNotificationCenter添加個類別,重寫他的- (void)removeObserver:(id)observer方法:

- (void)removeObserver:(id)observer

{

    NSLog(@"====%@

    remove===", [observer class]);

}

        這樣在我們VC中導入這個類別,然後pop出來,看看發生了什麼!

2015-01-19 22:59:00.580 測試[1181:288728] ====TestViewController remove===

        怎麼樣?是不是可以證明系統的UIViewController在銷燬的時候調用了這個方法。(不建議大家在開發的時候用類別的方式覆蓋原有的方法,由於類別方法具有更高的優先權,所以有可能影響到其他地方。這裏只是調試用)。

        以上也提醒我們,在你不是銷燬的時候,千萬不要直接調用[[NSNotificationCenter

defaultCenter] removeObserver: self]; 這個方法,因爲你有可能移除了系統註冊的通知


1.1.3 多線程通知

    首先看下蘋果的官方說明:

        Regular notification centers deliver notifications on the thread in which the notification was posted. Distributed notification centers deliver notifications on the main thread. At times, you may require notifications to be delivered on a particular thread that is determined by you instead of the notification center. 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.

        意思很簡單,NSNotificationCenter消息的接受線程是基於發送消息的線程的。也就是同步的,因此,有時候,你發送的消息可能不在主線程,而大家都知道操作UI必須在主線程,不然會出現不響應的情況。所以,在你收到消息通知的時候,注意選擇你要執行的線程。下面看個示例代碼

//接受消息通知的回調

- (void)test

{

    if ([[NSThreadcurrentThread] isMainThread]) {

        NSLog(@"main");

    }else{

        NSLog(@"not main");

    }

    dispatch_async(dispatch_get_main_queue(), ^{

        //do your UI

    });

}


//發送消息的線程

- (void)sendNotification

{

    dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(defaultQueue, ^{

        [[NSNotificationCenter defaultCenter] postNotificationName: @"test" object: nil];

    });

}


2 開發技巧

2.1 常用開發技巧

2.1.1 注意重複addObserver

    在我們開發中,我們經常可以看到這樣的代碼:

- (void)viewWillAppear:(BOOL)animated

{

    [super viewWillAppear: animated];

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

}


- (void)viewWillDisappear:(BOOL)animated

{

    [super viewWillDisappear :animated];

    [[NSNotificationCenter defaultCenter] removeObserver: self name:@"test" object: nil];

}

        就是在頁面出現的時候註冊通知,頁面消失時移除通知。你這邊可要注意了,一定要成雙成對出現,如果你只在viewWillAppear 中 addObserver沒有在viewWillDisappear 中 removeObserver那麼當消息發生的時候,你的方法會被調用多次,這點必須牢記在心。


3 參考鏈接

iOS NSNotificationCenter使用姿勢詳解

http://www.jianshu.com/p/a4d519e4e0d5


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章