問(wèn)題:在使用KVO的時(shí)候,如果在沒(méi)有添加監(jiān)聽(tīng)的情況下進(jìn)行觀察者移除,會(huì)導(dǎo)致程序的崩潰.
這個(gè)問(wèn)題看起來(lái)有點(diǎn)腦殘,如果沒(méi)有添加為什么還要移除, 但是我確實(shí)遇到了,它的情景是這樣的:
如上圖:這是一個(gè)典型的以UITabBarController為根控制器的應(yīng)用.
各個(gè)控制器的用途在圖中都有標(biāo)出,其中在C控制器中,如果用戶點(diǎn)擊了
退出登錄
按鈕,我的處理方式是切換程序的根控制器(如果不是這樣的做法可能就不會(huì)有這個(gè)問(wèn)題了).
問(wèn)題來(lái)了,當(dāng)我啟動(dòng)app的時(shí)候,由于A是默認(rèn)控制器, 就會(huì)首先執(zhí)行A控制器的viewDidLoad:方法, 而B控制器的viewDidLoad:方法在我們點(diǎn)擊按鈕B的時(shí)候才會(huì)調(diào)用,B控制器才會(huì)添加對(duì)KVO的監(jiān)聽(tīng).
當(dāng)然,我們也可以通過(guò)其他方法使B的viewDidLoad:方法提前調(diào)用,但這不在我們這篇文章的討論范圍.
那么,如果app啟動(dòng)后我沒(méi)有點(diǎn)擊B控制器而是直接進(jìn)入C控制器并點(diǎn)擊了退出登錄, 這時(shí)進(jìn)行了根控制器的切換,整個(gè)tabBarController都會(huì)被釋放,從而B控制器也就來(lái)到了dealloc方法(移除對(duì)KVO的監(jiān)聽(tīng)).這就是為什么,B控制器為什么會(huì)在沒(méi)有添加監(jiān)聽(tīng)的情況下就會(huì)被移除觀察者.
查了很久發(fā)現(xiàn)蘋果并沒(méi)有給我們提供一個(gè)判斷是否已經(jīng)添加觀察者的方法,最后不得不采取了這個(gè)比較猥瑣的方法:
// 在B控制器中
- (void)dealloc {
@try {
[[ATBlueTooth shareInstance] removeObserver:self forKeyPath:@"isBluetoothConnecting"];
}
@catch (NSException *exception) {
}
}