熟悉oc文法的同學也許都會懂得這麼一點:在oc中,類的成員變數或是方法是沒有絕對私人的。
私人方法直接通過類執行個體無法訪問,但可以藉助oc的“編譯運行時”機制,也即“瞎子摸黑”機制(個人理解:只要確定了該類有方法A,管你是私人共有,我用performSelector函數就能調用你),說到這,也許有同學會自然想起,那私人變數如何去訪問呢?貌似以前還真沒這樣搞過,然而現實是可以的,只不過一般我們把變數設為類的私人變數後是不希望自己或是其他人再去訪問的,不然我只能說你自己又在找賤了。。。。。。。。。。。。。。
好吧,言歸正傳,這篇文章主要是想介紹下oc中的KVC、KVO、KVB的實現機制,當然跟我上面說的那些肯定是有關係的啦。
1.KVC: key-value coding(索引值編碼)
它 是一種使用字串標識符,間接訪問對象屬性的機制,它是很多技術的基礎。主要的方法就兩對方法:(setValue:forKey,valueForKey)、setValue:forKeyPath,valueForKeyPath);這個東西有什麼作用呢,我先不說原理,先說怎麼用,例子如下:
@interface A { NSString* foo; }
... // 其它代碼
@end
@interface B { NSString* bar; A* myA; }
... // 其它代碼
@end
@implementation B
... // 假設 A 類型的對象 a,B 類型的對象
b A* a = ...;
B* b = ...;
NSString* s1 = [a valueForKey:@"foo"]; // 正確
NSString* s2 = [b valueForKey:@"bar"]; // 正確
NSString* s3 = [b valueForKey:@"myA"]; // 正確
NSString* s4 = [b valueForKeyPath:@"myA.foo"]; // 正確
NSString* s5 = [b valueForKey:@"myA.foo"]; // 錯誤
NSString* s6 = [b valueForKeyPath:@"bar"]; // 正確
...
@end
其實上面說的那兩對方法使用上基本是一樣的,只是valueForKeyPath的值是一個路徑(路徑之間以點號 . 分割),比如資料成員就是對象自己,尋值過程就會向下深入下去。
注意,這裡的資料成員的名字都是使用的字串的形式。這種使用方法的最好的用處在於將資料(名字)綁定到一些觸發器(尤其是方法調用)上,
例如索引值對觀察(Key-Value Observing, KVO)等。
上述代碼說明了類的成員變數也可以使用基類NSObject的那兩對方法去訪問,不一定直接通過類執行個體訪問,但是這種方式還是有一定的風險,具體危險情況請參考這個:http://www.devbean.info/2011/04/from_cpp_to_objc_20/
然後我再說下原理,是俺Copy過來的,大家觀賞下:
KVC運用了一個isa- swizzling技術。isa-swizzling就是類型混合指標機制。KVC主要通過isa- swizzling,來實現其內部尋找定位的。
isa指標,如其名稱所指,(就是is a kind of的意思),指向維護分發表的對象的類。該分發表實際上包含了指向實作類別中的方法的指標,和其它資料。
比如說如下的一行KVC的代碼:
[site setValue:@"sitename" forKey:@"name"];
就會被編譯器處理成:
SEL sel = sel_get_uid ("setValue:forKey:");
IMP method = objc_msg_lookup (site->isa,sel);
method(site, sel, @"sitename", @"name");
首先介紹兩個基本概念:
(1)SEL資料類型:它是編譯器運行Objective-C裡的方法的環境參數。
(2)IMP資料 類型:他其實就是一個編譯器內部實現時候的函數指標。當Objective-C編譯器去處理實現一個方法的時候,就會指向一個IMP對象,這個對象是C語言表述的類型(事實上,在Objective-C的編譯器處理的時候,基本上都是C語言的)。
這下KVC內部的實現就很清楚的清楚了:一個對象在調用setValue的時候,
(1)首先根據方法名找到運行方法的時候所需要的環境參 數。
(2)他會從自己isa指標結合環境參數,找到具體的方法實現的介面。
(3)再直接尋找得來的具體的方法實現。
2.KVO: key-value observing(索引值監聽)與KVB: key-value Binding(索引值綁定)
這兩個機制是結合起來使用的,分別說下,
Key-Value Observing (簡寫為KVO):當指定的對象的屬性被修改了,允許對象接受到通知的機制。每次指定的被觀察對象的屬性被修改的時候,KVO都會自動的去通知相應的觀察者。
KVO的優點
當 有屬性改變,KVO會提供自動的訊息通知。這樣的架構有很多好處。首先,開發人員不需要自己去實現這樣的方案:每次屬性改變了就發送訊息通知。這是KVO機制提供的最大的優點。因為這個方案已經被明確定義,獲得架構級支援,可以方便地採用。開發人員不需要添加任何代碼,不需要設計自己的觀察者模型,直接可以在工程裡使用。其次,KVO的架構非常的強大,可以很容易的支援多個觀察者觀察同一個屬性,以及相關的值。
KVB實現的兩個基本方法
1:為對象添加觀察者OBserver addObserver:forKeyPath:options:context:
2:觀察者OBserver收到資訊的處理函數 observeValueForKeyPath:ofObject:change:context:
KVO和KVB最明顯的使用情境就是在一些介面即時顯示行很強的地方,比如股票走向、售票餘額等,這種方式免去了我們自己操作通知的麻煩,想到這,我發現當初點金和91市場中下載頁面進度的顯示也完全可以採用這種方式。
先說到這兒吧,更精彩的待續。。。。。。。。
原英文連結:http://maniacdev.com/2012/12/helper-classes-for-easy-cocoa-touch-key-value-observing-kvo-and-key-value-binding-kvb/
1、setValue:forKey: 可以訪問到setXXX:方法。
2、valueForKey:可以訪問到執行個體變數和不帶參數的方法。
3、performSelector可以訪問所有方法。