序言
前幾天公交車上看了一篇百度大神的關(guān)于 KVO 探索的博客瘾晃。我實(shí)地驗(yàn)證了一下子贷痪,也遇到了好多問題,一番各種查閱資料之后蹦误,決定總結(jié)分享一下劫拢,供各位看官指點(diǎn)哈~
KVO 的原理
下面的原理仔細(xì)品嘗喔~多讀幾遍就可以理解了,當(dāng)然理解不了就按我說的來點(diǎn) KVO 的代碼强胰,最后腫能理解
PS:突然發(fā)現(xiàn)簡(jiǎn)書的 markdown 語法有點(diǎn)少舱沧,比如我想在對(duì)下面的 object 加粗時(shí)候,就找不到相應(yīng)的解決方法??
1.當(dāng)一個(gè) object(對(duì)象) 有觀察者時(shí)候偶洋,動(dòng)態(tài)創(chuàng)建這個(gè) object(對(duì)象) 的類的子類 2.對(duì)于每個(gè)被觀察的 property(屬性)熟吏,重寫其 setter 方法 3.在重寫的 setter 方法中調(diào)用 -willChangeValueForKey: 和 -didChangeValueForKey: 通知觀察者 4.當(dāng)一個(gè) property(屬性) 沒有觀察者時(shí),刪除重寫的方法 5.當(dāng)沒有 observer(觀察者) 觀察任何一個(gè) property(屬性) 時(shí)玄窝,刪除動(dòng)態(tài)創(chuàng)建的子類
Demo 驗(yàn)證
Demo 簡(jiǎn)單到要死牵寺,覺著扔一張圖就看的明白,比廢話一大堆簡(jiǎn)單多了恩脂,有時(shí)候看文字是件晦澀的事情缸剪,還得一個(gè)字一個(gè)字的理解,所以此處扔圖??东亦,有想看 Demo 的 點(diǎn)我穿越
接下來看看 KVO 是怎么動(dòng)態(tài)創(chuàng)建子類的:
斷點(diǎn)1—>代碼和 Log 日志
對(duì)比上述2張圖杏节,我們?cè)跀帱c(diǎn)1處唬渗,在控制臺(tái)分別使用- class
和 object_getClass()
打印person
對(duì)象的類和真實(shí)的類,下面的斷點(diǎn)2和斷點(diǎn)3都按此方法打印 Log日志奋渔。
斷點(diǎn)2—>代碼和 Log 日志
斷點(diǎn)3—>代碼和 Log 日志
瞧~镊逝,斷點(diǎn)2的 Log 日志信息突然冒出了一個(gè)
NSKVONotifying_HQMPerson
,這是什么鬼嫉鲸。撑蒜。。
我們知道為一個(gè)對(duì)象addObsever時(shí)候玄渗,也就是被觀察時(shí)座菠,
framework
使用runtime
動(dòng)態(tài)創(chuàng)建了一個(gè)HQMPerson
類的子類NSKVONotifying_HQMPerson
,而為了不讓外部知道這一行為藤树,
NSKVONotifying_HQMPerson
重寫了-class
方法返回之前的類浴滴,所以通過-class
方法查看的類沒有變化,但是通過object_getClass()
方式就會(huì)暴露出來發(fā)生了何種變化岁钓,因?yàn)檫@個(gè)object_getClass()
返回的是這個(gè)對(duì)象的isa
指針升略,isa指針指向的一定是這個(gè)對(duì)象所屬的類。如下圖:
常見錯(cuò)誤
?.錯(cuò)誤1-remove觀察者
造成該崩潰信息的代碼片段如下:
上述代碼是對(duì) person
這個(gè)對(duì)象添加了監(jiān)聽屡限,而removeObserver
方法卻是移除的self
品嚣,顯然這是一個(gè)很低級(jí)的錯(cuò)誤。
解決方法: 觀察誰钧大,誰就應(yīng)該移除
也就是偷窺誰翰撑,誰就發(fā)毛,所以就該跑
?.錯(cuò)誤2-屬性的值修改了的信息收到了啊央,但是并沒有處理
其實(shí)這個(gè)很簡(jiǎn)單就是你
addObserver
了眶诈,但是方法
-observeValueForKeyPath:ofObject:change:context:
卻沒有實(shí)現(xiàn),這個(gè)算是最低級(jí)的了??劣挫。。东帅。
解決方法:
PS:只要你注冊(cè)了 KVO压固,這個(gè)方法就必須實(shí)現(xiàn)
?.錯(cuò)誤3-添加和移除時(shí)候,context上下文不一致
代碼片段如下:
解決方法:
一般來說context都傳nil
?.錯(cuò)誤4-致命性
說實(shí)話遇到這個(gè)錯(cuò)誤靠闭,我還是真不知道從何入手(皆因?qū)?KVO 的理解不夠深)帐我,先看出現(xiàn)這種崩潰的原始代碼:
只要運(yùn)行,程序就會(huì)爽快的崩潰愧膀。拦键。¢萘埽看下我的注釋芬为,然后在對(duì)比一下崩潰日志信息(HQMPerson 類的實(shí)例被釋放了萄金,但是 KVO 中還有關(guān)于他的注冊(cè)信息)。
實(shí)際上媚朦,只要你明白 KVO 的知識(shí):在添加觀察者的時(shí)候氧敢,觀察者對(duì)象與被觀察的屬性所屬的對(duì)象都不會(huì)被retain,然而在這些對(duì)象被釋放后询张,相關(guān)的監(jiān)聽信息卻還存在孙乖,(ARC環(huán)境下)KVO做的處理是直接讓程序崩潰。
解決方法:
既然明白了這一點(diǎn)份氧,我們就知道如何修改了(ARC 環(huán)境下)唯袄,如下修改:
尾
關(guān)于 KVO 的觸發(fā)方式-自動(dòng)和手動(dòng),以及更深的底層探索待續(xù)喔蜗帜。恋拷。。會(huì)出 xxx(二) 呢(這部分得參考 apple 的官方文檔钮糖,英文有壓力??)
PS:碼一篇文章難梅掠,碼一篇好文好好難。馬丹店归,本來打算每周要寫一篇的甭管是多是少阎抒。哦。消痛。且叁。對(duì)了,馬丹...是個(gè)人名吶??