crash日志:
*** Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <XXXViewController 0x7ff158707f80> for the key path "xxx" from <XXXViewController 0x7ff158707f80> because it is not registered as an observer.'
分析原因:在使用KVO時,add observer和remove observer都是配對出現的,首先添加成為觀察者,然後在釋放記憶體的時候移除。例如:
override func viewDidLoad() {
super.viewDidLoad()
AppUnreadNumManager.instance.addObserver(self, forKeyPath: "xxx", options: .new, context: nil)
}
deinit {
AppUnreadNumManager.instance.removeObserver(self, forKeyPath: "xxx", context: nil)
}
通常情況下,這樣寫是沒有問題的,但是有時候控制器可能還沒有加載(viewDidLoad方法沒走),然後就被釋放了(deinit方法走了),這樣就會出現上面那個bug。
我項目中出現這個bug的原因是:我在某個控制器開啟KVO監聽,正好它又是UITabBarController的子控制器,在沒有選中該控制器的情況下,它的viewDidLoad方法是不會走的。如果這時候直接退出UITabBarController,那麼該控制器就會直接被釋放,這樣就會出現還沒添加觀察者就移除觀察者的bug。
解決方案:
var isViewDidLoad = false
override func viewDidLoad() {
super.viewDidLoad()
isViewDidLoad = true
AppUnreadNumManager.instance.addObserver(self, forKeyPath: "xxx", options: .new, context: nil)
}
deinit {
if isViewDidLoad {
AppUnreadNumManager.instance.removeObserver(self, forKeyPath: "xxx", context: nil)
}
}