KVO使用過程中的陷阱
轉自
http://www.cnblogs.com/wengzilin/p/4346775.html
KVO,全稱為Key-Value Observing,是iOS中的一種設計模式,用于檢測對象的某些屬性的實時變化情況并作出響應。網上廣為流傳普及的一個例子是利用KVO檢測股票價格的變動,例如這裡。這個例子作為掃盲入門還是可以的,但是當應用場景比較複雜時,裡面的一些細節還是需要改進的,裡面有多個地方存在crash的危險。本文旨在逐漸遞進深入地探讨出一種目前比較健壯穩定的KVO實作方案,彌補網上大部分教程的不足!
首先,假設我們的目标是在一個UITableViewController内對tableview的contentOffset進行實時監測,很容易地使用KVO來實作為。
在初始化方法中加入:
1 | |
在dealloc中移除KVO監聽:
1 | |
添加預設的響應回調方法:
1 2 3 4 5 | |
好了,KVO實作就到此完美結束了,拜拜。。。開個玩笑,肯定沒這麼簡單的,這樣的代碼太粗糙了,當你在controller中添加多個KVO時,所有的回調都是走同上述函數,那就必須對觸發回調函數的來源進行判斷。判斷如下:
1 2 3 4 | |
1 | |
1 | |
你以為這樣就結束了嗎?答案是否定的!我們假設目前類(在例子中為UITableViewController)還有父類,并且父類也有自己綁定了一些其他KVO呢?我們看到,上述回調函數體中隻有一個判斷,如果這個if不成立,這次KVO事件的觸發就會到此中斷了。但事實上,若目前類無法捕捉到這個KVO,那很有可能是在他的superClass,或者super-superClass...中,上述處理砍斷了這個鍊。合理的處理方式應該是這樣的:
1 2 3 4 5 6 7 8 9 | |
這樣就結束了嗎?答案仍舊是否定的。潛在的問題有可能出現在dealloc中對KVO的登出上。KVO的一種缺陷(其實不能稱為缺陷,應該稱為特性)是,當對同一個keypath進行兩次removeObserver時會導緻程式crash,這種情況常常出現在父類有一個kvo,父類在dealloc中remove了一次,子類又remove了一次的情況下。不要以為這種情況很少出現!當你封裝framework開源給别人用或者多人協作開發時是有可能出現的,而且這種crash很難發現。不知道你發現沒,目前的代碼中context字段都是nil,那能否利用該字段來辨別出到底kvo是superClass注冊的,還是self注冊的。未完待續...