1.KVO是基于runtime機(jī)制實(shí)現(xiàn)的
2.當(dāng)某個(gè)類的屬性對(duì)象第一次被觀察時(shí)沟于,系統(tǒng)就會(huì)在運(yùn)行期動(dòng)態(tài)地創(chuàng)建該類的一個(gè)派生類摩梧,在這個(gè)派生類中重寫基類中任何被觀察屬性的setter 方法。派生類在被重寫的setter方法內(nèi)實(shí)現(xiàn)真正的通知機(jī)制
3.如果原類為Person祭阀,那么生成的派生類名為NSKVONotifying_Person
4.每個(gè)類對(duì)象中都有一個(gè)isa指針指向當(dāng)前類,當(dāng)一個(gè)類對(duì)象的第一次被觀察,那么系統(tǒng)會(huì)偷偷將isa指針指向動(dòng)態(tài)生成的派生類回右,從而在給被監(jiān)控屬性賦值時(shí)執(zhí)行的是派生類的setter方法
5.鍵值觀察通知依賴于NSObject 的兩個(gè)方法: willChangeValueForKey: 和 didChangevlueForKey:;在一個(gè)被觀察屬性發(fā)生改變之前漱挚, willChangeValueForKey:一定會(huì)被調(diào)用翔烁,這就 會(huì)記錄舊的值。而當(dāng)改變發(fā)生后旨涝,didChangeValueForKey:會(huì)被調(diào)用蹬屹,繼而 observeValueForKey:ofObject:change:context: 也會(huì)被調(diào)用。
KVO深入原理
1.Apple 使用了 isa 混寫(isa-swizzling)來實(shí)現(xiàn) KVO 。當(dāng)觀察對(duì)象A時(shí)慨默,KVO機(jī)制動(dòng)態(tài)創(chuàng)建一個(gè)新的名為:?NSKVONotifying_A的新類贩耐,該類繼承自對(duì)象A的本類,且KVO為NSKVONotifying_A重寫觀察屬性的setter?方法厦取,setter?方法會(huì)負(fù)責(zé)在調(diào)用原?setter?方法之前和之后潮太,通知所有觀察對(duì)象屬性值的更改情況。
2.NSKVONotifying_A類剖析:在這個(gè)過程虾攻,被觀察對(duì)象的 isa 指針從指向原來的A類铡买,被KVO機(jī)制修改為指向系統(tǒng)新創(chuàng)建的子類 NSKVONotifying_A類,來實(shí)現(xiàn)當(dāng)前類屬性值改變的監(jiān)聽霎箍;
3.所以當(dāng)我們從應(yīng)用層面上看來奇钞,完全沒有意識(shí)到有新的類出現(xiàn),這是系統(tǒng)“隱瞞”了對(duì)KVO的底層實(shí)現(xiàn)過程漂坏,讓我們誤以為還是原來的類景埃。但是此時(shí)如果我們創(chuàng)建一個(gè)新的名為“NSKVONotifying_A”的類(),就會(huì)發(fā)現(xiàn)系統(tǒng)運(yùn)行到注冊(cè)KVO的那段代碼時(shí)程序就崩潰顶别,因?yàn)橄到y(tǒng)在注冊(cè)監(jiān)聽的時(shí)候動(dòng)態(tài)創(chuàng)建了名為NSKVONotifying_A的中間類纠亚,并指向這個(gè)中間類了。
4.(isa 指針的作用:每個(gè)對(duì)象都有isa 指針筋夏,指向該對(duì)象的類蒂胞,它告訴 Runtime 系統(tǒng)這個(gè)對(duì)象的類是什么。所以對(duì)象注冊(cè)為觀察者時(shí)条篷,isa指針指向新子類骗随,那么這個(gè)被觀察的對(duì)象就神奇地變成新子類的對(duì)象(或?qū)嵗┝恕#?因而在該對(duì)象上對(duì) setter 的調(diào)用就會(huì)調(diào)用已重寫的 setter赴叹,從而激活鍵值通知機(jī)制鸿染。
5.子類setter方法剖析:KVO的鍵值觀察通知依賴于 NSObject 的兩個(gè)方法:willChangeValueForKey:和 didChangevlueForKey:,在存取數(shù)值的前后分別調(diào)用2個(gè)方法: 被觀察屬性發(fā)生改變之前乞巧,willChangeValueForKey:被調(diào)用涨椒,通知系統(tǒng)該 keyPath?的屬性值即將變更;當(dāng)改變發(fā)生后绽媒, didChangeValueForKey: 被調(diào)用蚕冬,通知系統(tǒng)該 keyPath?的屬性值已經(jīng)變更;之后是辕,?observeValueForKey:ofObject:change:context: 也會(huì)被調(diào)用囤热。且重寫觀察屬性的setter?方法這種繼承方式的注入是在運(yùn)行時(shí)而不是編譯時(shí)實(shí)現(xiàn)的。