Kvc簡(jiǎn)介:
KVC(Key-value coding)鍵值編碼温亲,顧名思義栈虚。額史隆,簡(jiǎn)單來(lái)說(shuō),是可以通過(guò)對(duì)象屬性名稱(Key)直接給屬性值(value)編碼(coding)“編碼”可以理解為“賦值”粘姜。這樣可以免去我們調(diào)用getter和setter方法相艇,從而簡(jiǎn)化我們的代碼纯陨,也可以用來(lái)修改系統(tǒng)控件內(nèi)部屬性(這個(gè)黑魔法且用且珍惜)测柠。
舉例:
如果不使用kvc我們正常使用是:
使用kvc的話是:
上面介紹了基本的kvc使用方法获讳,下面我們來(lái)學(xué)習(xí)一下他的原理:
kvc取值的底層原理
引入:
假如我們使用kvc取值丐膝,
這時(shí)候運(yùn)行的話肯定會(huì)報(bào)錯(cuò),回報(bào)未定義的崩潰錯(cuò)誤偎肃,那么我們接下來(lái)學(xué)習(xí)kvc他是怎么找的:
比如我們的
1》我們kvc在底層可不是僅僅找name這個(gè)key累颂,他一共會(huì)找四個(gè)key,四個(gè)key的分別是:
_name _isName name isName
這四個(gè)key的優(yōu)先級(jí)是從高到低依次是_name _isName name isName
如果這四個(gè)都沒(méi)有那么就會(huì)遇到上面說(shuō)的崩潰報(bào)錯(cuò)了
2》你以為到這里就結(jié)束了嗎料饥?
其實(shí)這個(gè)valueForKey:方法 不止找這幾個(gè)成員變量朱监,他還會(huì)找下面這個(gè)方法:
如果返回值是YES,他才去找那四個(gè)成員變量赫编,如果是NO的話就不會(huì)去找那四個(gè)成員變量(即使定義的有),直接崩潰錯(cuò)誤赡若。
3》 你以為到這里又結(jié)束了嗎团甲?
這個(gè)valueForKey:方法其實(shí)還會(huì)找其他東西的,拿他去找什么的身腻,他其實(shí)還會(huì)找getter方法(getter是個(gè)復(fù)數(shù))匹厘,會(huì)找那些get方法呢,如下:
這三個(gè)方法的優(yōu)先級(jí)是:name她按,isName炕柔,getName
4》到此還沒(méi)有完,他還會(huì)找兩個(gè)方法陵刹,如下:
如果他找了這兩個(gè)方法衰琐,會(huì)輸出什么呢炼蹦,會(huì)輸出個(gè)數(shù)組,這個(gè)數(shù)組里面是10個(gè)字符串“haha”
5》辛辨,上面的還不完整,其實(shí)還可能會(huì)走一個(gè)方法指攒。
即如果走到了2》僻焚,但是2》返回值為no,就自己餓會(huì)崩潰隙弛,如果我們不想崩潰的話狞山,就重寫這個(gè)方法
至此算是全部結(jié)束,你會(huì)疑問(wèn)1》 2》 3》 4》這么多kvc都要去找总珠,那么具體順序是什么呢勘纯?下面我們來(lái)總結(jié)一下這個(gè)具體順序
關(guān)于KVC valueForKey:key 的調(diào)用查找順序
|-先調(diào)用“相關(guān)”方法,先后順序是:
1》|-getter方法淫奔,getKey -> key -> isKey (注意字母大小寫)
2》|- NSArray方法:countOfKey 和objectInKeyAtIndex
|-如果沒(méi)有相關(guān)方法堤结,會(huì)找2》也就是看+(BOOL)accessInstanceVariablesDirectly 返回值
1 》 |-YES 的話去找成員變量1》,順序依次是_key -> _isKey -> key -> isKey
2 》 |-NO 的話就直接拋崩潰異常了媒惕。但是蘋果還給了我們一個(gè)救火的方法来庭,如果這個(gè)返回值是no月弛,但是我們還不想崩潰怎么辦科盛,我們就只能重寫valueForUndefinedKey,返回值為nil,這樣就不會(huì)崩潰了
OK厉萝,到這里我們總結(jié)了關(guān)于kvc取值查找的過(guò)程,算了還是在用語(yǔ)言描述一下加深下印象吧章母,
文字總結(jié):我們通過(guò)kvc的valueForKey:key方法去取值的時(shí)候翩剪,首先我們回去找getter的那三個(gè)方法,找到的話按照優(yōu)先級(jí)得到值蚪缀,如果三個(gè)getter方法沒(méi)有話的恕出,kvc會(huì)繼續(xù)找NSArray方法,就是countOfKey 和objectInKeyAtIndex 他們兩個(gè)金蜀,如果有的話就返回個(gè)數(shù)組狈醉。如果這兩個(gè)NSArray方法也沒(méi)有的話,我們會(huì)繼續(xù)去找抒线,繼續(xù)去找+(BOOL)accessInstanceVariablesDirectly這個(gè)返回值為bool類型的方法渣慕,如果他的返回值是yes,那么我們就去找哪四個(gè)成員變量眨猎,也是按照優(yōu)先級(jí)取值;如果+(BOOL)accessInstanceVariablesDirectly這個(gè)返回值為no的話睡陪,就不去找那四個(gè)成員變量了匿情,回去找看有沒(méi)有重載valueForUndefinedKey這個(gè)方法,按照要求重載了的話不會(huì)崩潰汁果,kvc這個(gè)valueForKey:key會(huì)得到一個(gè)null值玲躯,如果沒(méi)有重載這個(gè)方法鳄乏,那么就會(huì)直接崩潰
ps:對(duì)于valueForKeyPath:path,這種點(diǎn)點(diǎn)點(diǎn)下去的路徑key橱野,和其他的原理一樣
kvc設(shè)值的底層原理
[model setValue:@"kvcName" forKeyPath:@"name"];
通過(guò)我們上面kvc的取值的學(xué)習(xí)赡译,這里kvc的設(shè)值也是需要找的,那她找的順序是什么呢裹唆?
-
1.setter相關(guān)方法
image.png
setter的方法就這兩個(gè)许帐,他們的優(yōu)先級(jí)為setName -> setIsName
- 找成員變量_name -> _isName -> name -> isName
- 和取值一樣也要看+(BOOL)accessInstanceVariablesDirectly這個(gè)方法的返回值
-
去取值一樣也有個(gè)救火的方法:
image.png -
如果我們給一個(gè)基本數(shù)據(jù)類型通過(guò)kvc設(shè)值毕谴,value給了一個(gè)nil,那么直接就會(huì)崩了循帐,所以還有個(gè)異常處理方法來(lái)防治這個(gè)崩潰
image.png
至此kvc的設(shè)值就結(jié)束了拄养,我們來(lái)總結(jié)一下他的過(guò)程
- 尋找setter的兩個(gè)方法
- 如果setter的兩個(gè)方法都沒(méi)有银舱,看+(BOOL)accessInstanceVariablesDirectly這個(gè)方法的返回值方法的返回值
YES 去找四個(gè)成員變量
NO 去找valueForUndefinedKey,有的話不會(huì)崩潰寻馏,沒(méi)有的話會(huì)崩潰
- 對(duì)于基本數(shù)據(jù)類型的setValue:value forKey:key,如果value為nil的話他會(huì)直接崩潰,所以kvc在基本數(shù)據(jù)類型value為nil的時(shí)候還回去找setNilValueForKey這個(gè)方法是否重載實(shí)現(xiàn)了顽染,如果重載了就不會(huì)崩潰轰绵,否則會(huì)崩潰
自定義一個(gè)kvc, 不使用系統(tǒng)的kvc
首先我們想一下系統(tǒng)的kvc是不是任何類都可以使用,所以系統(tǒng)的kvc是不是肯定是寫在NSObject的分類里面呢耀找,所以我們自定的話就先新建一個(gè)NSObject的分類
-
我們自定義取值和設(shè)值的方法
image.png -
來(lái)實(shí)現(xiàn)這兩個(gè)方法,先看實(shí)現(xiàn)set的方法
image.png
image.png
image.png
image.png
寫的時(shí)候可以自己通過(guò)自定的Person類和vc中測(cè)試一下
下面是自己測(cè)試的部分代碼:
image.png
image.png
image.png
自己自定義的kvc設(shè)置值的方法,其實(shí)也就是按照上面學(xué)的邏輯來(lái)寫的妇斤,kvc取值的就不在寫了丹拯,比較簡(jiǎn)單,就不在這里重復(fù)了