當(dāng)觀察某對象A的時候,KVO機(jī)制動態(tài)創(chuàng)建一個對象A當(dāng)前類的子類,并未這個新的子類重寫了被觀察屬性keyPath的setter方法,setter方法隨后負(fù)責(zé)通知觀察對象屬性的改變狀況
剖析
Apple使用了isa混寫(isa-swizzling)來實現(xiàn)KVO。當(dāng)觀察對象A的時候,KVO動態(tài)創(chuàng)建一個新的名為:NSKVONotifying_A的新類,該類繼承自對象A的本類,且KVO為NSKVONotifying_A重寫觀察屬性的setter方法,setter方法會負(fù)責(zé)在調(diào)用原setter方法之前和之后,通知所有觀察對象屬性的更改情況.
-
NSKVONotifying_A類的剖析
在這個過程,被觀察對象的isa指針從指向原來的A類,被KVO機(jī)制修改為指向系統(tǒng)新創(chuàng)建的子類NSKVONotifying_A類,來實現(xiàn)當(dāng)前類屬性值改變的監(jiān)聽;
所以當(dāng)我們從應(yīng)用層面上看來,完全沒有意識到有新的類出現(xiàn),這是系統(tǒng)“隱瞞”了對KVO的底層實現(xiàn)過程,讓我們誤以為還是原來的類。但是此時如果我們創(chuàng)建一個新的名為“NSKVONotifying_A”的類(),就會發(fā)現(xiàn)系統(tǒng)運行到注冊KVO的那段代碼時程序就崩潰,因為系統(tǒng)在注冊監(jiān)聽的時候動態(tài)創(chuàng)建了名為NSKVONotifying_A的中間類,并指向這個中間類了。
-
子類setter方法剖析
KVO的鍵值觀察通知依賴于 NSObject 的兩個方法:willChangeValueForKey:
和 didChangeValueForKey:
,在存取數(shù)值的前后分別調(diào)用2個方法:被觀察屬性發(fā)生改變之前,willChangeValueForKey:被調(diào)用,通知系統(tǒng)該 keyPath 的屬性值即將變更;當(dāng)改變發(fā)生后, didChangeValueForKey: 被調(diào)用,通知系統(tǒng)該 keyPath 的屬性值已經(jīng)變更;之后, observeValueForKey:ofObject:change:context:
也會被調(diào)用。且重寫觀察屬性的setter 方法這種繼承方式的注入是在運行時而不是編譯時實現(xiàn)的。