1. 函數調用(消息)實現分析: ios
咱們看這條語句: c#
1 | [self.person setValue:@"Vincent"forKey:@"name"]; |
就會被編譯器處理成: 框架
1 | SEL sel = sel_get_uid ("setValue:forKey:"); |
2 |
3 | IMP method = objc_msg_lookup (self.person->isa,sel); |
4 |
5 | method(self.person, sel,@"Vincent",@"name"); |
也就是說iOS中函數調用並非被靜態編譯爲地址調用,而是被轉爲查表、調用! 函數
2. 這裏須要介紹幾個基本概念: ui
(1). SEL數據類型:它是編譯器運行Objective-C裏的方法的環境參數。 spa
(2). IMP數據類型:他其實就是一個 編譯器內部實現時候的函數指針。當Objective-C編譯器去處理實現一個方法的時候,就會指向一個IMP對象,這個對象是C語言表述的類型(事實上,在Objective-C的編譯器處理的時候,基本上都是C語言的)。 debug
(3). isa指針,如其名稱所指,(就是is a kind of的意思),指向維護分發表的對象的類。該分發表實際上包含了指向實現類中的方法的指針,和其它數據。 指針
3. KVO/KVC實現分析: 調試
當咱們爲一個類的某個屬性添加observer時候,框架自動建立這個類的一個子類,而且修改這個類的isa指向這個新的子類。 server
因爲在ios中函數調用都是轉化爲isa查表形式,因此此次查得時新的子類的表,
也就是說對類的函數調用被子類給攔截了,在攔截的實現中就能夠通知observer了。
修改類的isa被稱爲isa-swizzling技術。isa-swizzling就是類型混合指針機制。KVC主要經過isa-swizzling,來實現其內部查找定位的。
好比仍是這段代碼:
1 | [self.person setValue:@"Vincent"forKey:@"name"]; |
它會被編譯爲:
1 | SEL sel = sel_get_uid ("setValue:forKey:"); |
2 |
3 | IMP method = objc_msg_lookup (self.person->isa,sel); |
4 |
5 | method(self.person, sel,@"Vincent",@"name"); |
這裏的isa是動態生成的子類,你debugger調試一個被觀察的類就會發現它的isa已經發生了變化!而沒有被觀察的類的isa是正常的,如圖所示:
也就是說咱們調用setValue...的時候實際上已經調用observer的didChangeValueForKey:方法!
由於KVC的實現機制,能夠很容易看到某個KVC操做的Key,然後也很容易的跟觀察者註冊表中的Key進行匹對。假如訪問的Key是被觀察的Key,那麼咱們在內部就能夠很容易的到觀察者註冊表中去找到觀察者對象,然後給他發送消息。