KVC和KVO都屬于鍵值編程而且底層實(shí)現(xiàn)機(jī)制都是isa-swizzing,所以本來想放在一起講的炮障。但是篇幅有限所以就分成了兩篇博文 KVO實(shí)現(xiàn)機(jī)制
KVC概述
- KVC是Key Value Coding的簡稱。它是一種可以通過字符串的名字(key)來訪問類屬性的機(jī)制宅此。而不是通過調(diào)用Setter垒棋、Getter方法訪問。
- 關(guān)鍵方法定義在 NSKeyValueCodingProtocol
- KVC支持類對(duì)象和內(nèi)建基本數(shù)據(jù)類型偏螺。
KVC使用
獲取值
valueForKey: 傳入NSString屬性的名字行疏。
valueForKeyPath: 屬性的路徑,xx.xx
valueForUndefinedKey 默認(rèn)實(shí)現(xiàn)是拋出異常套像,可重寫這個(gè)函數(shù)做錯(cuò)誤處理修改值
setValue:forKey:
setValue:forKeyPath:
setValue:forUnderfinedKey:
setNilValueForKey: 對(duì)非類對(duì)象屬性設(shè)置nil時(shí)調(diào)用酿联,默認(rèn)拋出異常。
KVC鍵值查找
搜索單值成員
-
setValue:forKey:搜索方式
1夺巩、首先搜索setKey:方法贞让。(key指成員變量名,首字母大寫)
2柳譬、上面的setter方法沒找到喳张,如果類方法accessInstanceVariablesDirectly返回YES。那么按 _key美澳,_isKey销部,key,iskey的順序搜索成員名制跟。(NSKeyValueCodingCatogery中實(shí)現(xiàn)的類方法舅桩,默認(rèn)實(shí)現(xiàn)為返回YES)
3、如果沒有找到成員變量雨膨,調(diào)用setValue:forUnderfinedKey:
-
valueForKey:的搜索方式
1擂涛、首先按getKey,key哥放,isKey的順序查找getter方法歼指,找到直接調(diào)用爹土。如果是BOOL、int等內(nèi)建值類型踩身,會(huì)做NSNumber的轉(zhuǎn)換胀茵。
2、上面的getter沒找到挟阻,查找countOfKey琼娘、objectInKeyAtindex、KeyAtindexes格式的方法附鸽。如果countOfKey和另外兩個(gè)方法中的一個(gè)找到脱拼,那么就會(huì)返回一個(gè)可以響應(yīng)NSArray所有方法的代理集合的NSArray消息方法。
3坷备、還沒找到熄浓,查找countOfKey、enumeratorOfKey省撑、memberOfKey格式的方法赌蔑。如果這三個(gè)方法都找到,那么就返回一個(gè)可以響應(yīng)NSSet所有方法的代理集合竟秫。
4娃惯、還是沒找到,如果類方法accessInstanceVariablesDirectly返回YES肥败。那么按 _key趾浅,_isKey,key馒稍,iskey的順序搜索成員名皿哨。5、再?zèng)]找到筷黔,調(diào)用valueForUndefinedKey往史。
KVC實(shí)現(xiàn)分析
KVC運(yùn)用了isa-swizzing技術(shù)。isa-swizzing就是類型混合指針機(jī)制佛舱。KVC通過isa-swizzing實(shí)現(xiàn)其內(nèi)部查找定位。isa指針(is kind of 的意思)指向維護(hù)分發(fā)表的對(duì)象的類挨决,該分發(fā)表實(shí)際上包含了指向?qū)崿F(xiàn)類中的方法的指針和其他數(shù)據(jù)请祖。
比如說如下的一行KVC代碼:
[site setValue:@"sitename" forKey:@"name"];
//會(huì)被編譯器處理成
SEL sel = sel_get_uid(setValue:forKey);
IMP method = objc_msg_loopup(site->isa,sel);
method(site,sel,@"sitename",@"name");
每個(gè)類都有一張方法表,是一個(gè)hash表脖祈,值是還書指針I(yè)MP肆捕,SEL的名稱就是查表時(shí)所用的鍵。
SEL數(shù)據(jù)類型:查找方法表時(shí)所用的鍵盖高。定義成char*慎陵,實(shí)質(zhì)上可以理解成int值眼虱。
IMP數(shù)據(jù)類型:他其實(shí)就是一個(gè)編譯器內(nèi)部實(shí)現(xiàn)時(shí)候的函數(shù)指針。當(dāng)Objective-C編譯器去處理實(shí)現(xiàn)一個(gè)方法的時(shí)候席纽,就會(huì)指向一個(gè)IMP對(duì)象捏悬,這個(gè)對(duì)象是C語言表述的類型。
KVC的內(nèi)部機(jī)制:
一個(gè)對(duì)象在調(diào)用setValue的時(shí)候進(jìn)行了如下操作:
- (1)根據(jù)方法名找到運(yùn)行方法的時(shí)候需要的環(huán)境參數(shù)
- (2)他會(huì)從自己的isa指針結(jié)合環(huán)境參數(shù)润梯,找到具體的方法實(shí)現(xiàn)接口过牙。
- (3)再直接查找得來的具體的實(shí)現(xiàn)方法