序言
前幾天公交車上看了一篇百度大神的關于 KVO 探索的博客。我實地驗證了一下子,也遇到了好多問題,一番各種查閱資料之后,決定總結分享一下,供各位看官指點哈~
KVO 的原理
下面的原理仔細品嘗喔~多讀幾遍就可以理解了,當然理解不了就按我說的來點 KVO 的代碼,最后腫能理解
PS:突然發(fā)現(xiàn)簡書的 markdown 語法有點少,比如我想在對下面的 object 加粗時候,就找不到相應的解決方法??
1.當一個 object(對象) 有觀察者時候,動態(tài)創(chuàng)建這個 object(對象) 的類的子類 2.對于每個被觀察的 property(屬性),重寫其 setter 方法 3.在重寫的 setter 方法中調(diào)用 -willChangeValueForKey: 和 -didChangeValueForKey: 通知觀察者 4.當一個 property(屬性) 沒有觀察者時,刪除重寫的方法 5.當沒有 observer(觀察者) 觀察任何一個 property(屬性) 時,刪除動態(tài)創(chuàng)建的子類
Demo 驗證
Demo 簡單到要死,覺著扔一張圖就看的明白,比廢話一大堆簡單多了,有時候看文字是件晦澀的事情,還得一個字一個字的理解,所以此處扔圖??,有想看 Demo 的 點我穿越

接下來看看 KVO 是怎么動態(tài)創(chuàng)建子類的:
斷點1—>代碼和 Log 日志


對比上述2張圖,我們在斷點1處,在控制臺分別使用- class 和 object_getClass() 打印person對象的類和真實的類,下面的斷點2和斷點3都按此方法打印 Log日志。
斷點2—>代碼和 Log 日志


斷點3—>代碼和 Log 日志


瞧~,斷點2的 Log 日志信息突然冒出了一個
NSKVONotifying_HQMPerson,這是什么鬼。。。
我們知道為一個對象addObsever時候,也就是被觀察時,
framework使用runtime動態(tài)創(chuàng)建了一個HQMPerson類的子類NSKVONotifying_HQMPerson,而為了不讓外部知道這一行為,
NSKVONotifying_HQMPerson重寫了-class方法返回之前的類,所以通過-class方法查看的類沒有變化,但是通過object_getClass()方式就會暴露出來發(fā)生了何種變化,因為這個object_getClass()返回的是這個對象的isa指針,isa指針指向的一定是這個對象所屬的類。如下圖:

常見錯誤
?.錯誤1-remove觀察者

造成該崩潰信息的代碼片段如下:

上述代碼是對 person 這個對象添加了監(jiān)聽,而removeObserver方法卻是移除的self,顯然這是一個很低級的錯誤。
解決方法: 觀察誰,誰就應該移除也就是偷窺誰,誰就發(fā)毛,所以就該跑
?.錯誤2-屬性的值修改了的信息收到了,但是并沒有處理

其實這個很簡單就是你
addObserver了,但是方法
-observeValueForKeyPath:ofObject:change:context:卻沒有實現(xiàn),這個算是最低級的了??。。。
解決方法:
PS:只要你注冊了 KVO,這個方法就必須實現(xiàn)
?.錯誤3-添加和移除時候,context上下文不一致

代碼片段如下:

解決方法:
一般來說context都傳nil
?.錯誤4-致命性

說實話遇到這個錯誤,我還是真不知道從何入手(皆因?qū)?KVO 的理解不夠深),先看出現(xiàn)這種崩潰的原始代碼:

只要運行,程序就會爽快的崩潰。。??聪挛业淖⑨專缓笤趯Ρ纫幌卤罎⑷罩拘畔?HQMPerson 類的實例被釋放了,但是 KVO 中還有關于他的注冊信息)。
實際上,只要你明白 KVO 的知識:在添加觀察者的時候,觀察者對象與被觀察的屬性所屬的對象都不會被retain,然而在這些對象被釋放后,相關的監(jiān)聽信息卻還存在,(ARC環(huán)境下)KVO做的處理是直接讓程序崩潰。
解決方法:
既然明白了這一點,我們就知道如何修改了(ARC 環(huán)境下),如下修改:

尾
關于 KVO 的觸發(fā)方式-自動和手動,以及更深的底層探索待續(xù)喔。。。會出 xxx(二) 呢(這部分得參考 apple 的官方文檔,英文有壓力??)
PS:碼一篇文章難,碼一篇好文好好難。馬丹,本來打算每周要寫一篇的甭管是多是少。哦。。。對了,馬丹...是個人名吶??