iOS中的KVC,我們都熟記于心了,它的用法一般就是 setValue這樣的用法
一、KVC之用法
- 我們在代碼里用一下setValue
1、對基本類型使用kvc
image.png
可以點(diǎn)進(jìn)setValue看一下源碼實現(xiàn)
image.png
發(fā)現(xiàn)是在foudation框架里NSObject的分類NSKeyValueCoding.h中的方法,所以只要是繼承于NSObject的所有類都是可以使用KVC的。而foundation是閉源的,所以只能去到官方文檔查找相關(guān)分析

以上文檔大致的意思是:
對象從NSObject繼承(直接或間接)時通常會采用KVC,它們都采用NSKeyValueCoding協(xié)議并提供基本方法的默認(rèn)實現(xiàn)。這樣的對象通過一個緊湊的消息傳遞接口使其他對象能夠執(zhí)行以下操作:
【1】訪問對象屬性:協(xié)議指定方法來通過把名字或鍵參數(shù)化為字符串來訪問對象屬性,例如一般的getter valueForKey:和一般的setter setValue:forKey:
【2】操作集合屬性:訪問器方法的默認(rèn)實現(xiàn)使用對象的集合屬性和任何其他屬性一樣。另外,如果對象為屬性定義了集合訪問器方法,則它允許鍵值訪問集合內(nèi)容。這樣通常比直接訪問更有效,并且允許你通過標(biāo)準(zhǔn)的接口來使用自定義集合對象,正如 Accessing Collection Properties 所述。
【3】在集合對象上調(diào)用集合操作符:一個符合KVC的對象的集合屬性時,你可以把一個集合操作符插入到鍵字符串中,正如 Using Collection Operators 所述。集合操作符指示默認(rèn)的NSKeyValueCodinggetter實現(xiàn)對集合進(jìn)行操作,然后返回一個新的集合的過濾版本,或者表示集合某些特征的單個值。
【4】訪問非對象屬性。協(xié)議的默認(rèn)實現(xiàn)檢測非對象屬性,包括標(biāo)量和結(jié)構(gòu)體,并自動把他們包裝或解包為協(xié)議接口使用的對象,正如 Representing Non-Object Values 所述。另外,該協(xié)議聲明了一個方法,該方法允許兼容對象通過KVC接口在非對象屬性上設(shè)置一個nil值時做出合適的操作。(主要針對結(jié)構(gòu)體)
【5】用過keypath的形式訪問屬性
具有符合KVC的對象的層次結(jié)構(gòu),可以使用基于key path的方法調(diào)用,使用單個調(diào)用在層次結(jié)構(gòu)中深入查看,獲取或設(shè)置值。
2、第一種已經(jīng)試過,是通常使用到的方法。下面我們試試剩下的幾種方法
第二種:操作集合,就以NSArray為例:在person中設(shè)置一個array,修改其中第一個元素的值:

第三種:
array取值

聚合操作符


第四種:可以操作結(jié)構(gòu)體
定義一個結(jié)構(gòu)體
typedef struct {
float x, y, z;
} ThreeFloats;
賦值和調(diào)用

第五種:keypath方式:用路由的方式進(jìn)行訪問屬性:lgperson里定義一個lgstudent類型的屬性subject,給lgstudent的屬性student賦值,可以通過person的keypath直接訪問到student值

二、KVC調(diào)用原理
- 先以最常用的
setValue方法來分析
還是到kvc官方文檔里去找到set方法的調(diào)用流程
image.png
以上大致流程是:先找到set方法或者_(dá)set方法->accessInstanceVariablesDirectly(關(guān)閉或開啟實例變量賦值)->setValue:forUndefinedKey
先將accessInstanceVariablesDirectly設(shè)置為YES,其實這個方法在系統(tǒng)中默認(rèn)就是YES,當(dāng)認(rèn)為設(shè)置為NO時,系統(tǒng)會報錯
image.png


通過對person->_name,person->_isName,person->name,person->isName不同值的調(diào)試,可以印證文檔里的調(diào)用順序
_<key>-> _is<Key>-><key>->is<Key>,

-
再分析一下get的調(diào)用順序
image.png
先定義一些get方法
image.png
以上流程:先去找getter方法- >是否是集合類型- >->是否實現(xiàn)accessInstanceVariablesDirectly->普通類型(是否已經(jīng)賦值)->間接變量
getter方法順序:
get<Key>-><key>->is<Key>->_<key>
---->如果沒有getter方法,查找是否是集合類型,如果是集合類型,則走集合方法
----->如果是普通類型
----->判斷accessInstanceVariablesDirectly是否為yes
----->yes的話,就去查看賦值的key是否存在,按照_<key>->_is<Key>-><key>->is<Key>順序得到值。
------>NO的話,則走valueForUndefinedKey
三、自定義KVC
按照流程
自定義setValue方法
set方法是否存在
1、存在:執(zhí)行set方法
2、不存在:accessInstanceVariablesDirectly是否關(guān)閉,關(guān)閉的話,報錯。
3、accessInstanceVariablesDirectly沒有關(guān)閉,給設(shè)置屬性值
設(shè)置自定義NSObject分類(KVC的實現(xiàn))自定義
get方法
get系列方法是否存在
1、存在:執(zhí)行g(shù)et方法 (get<Key><key>countOf<Key>objectIn<Key>AtIndex)
2、不存在:判斷是否能夠直接賦值實例變量,如果不能夠直接賦值實例變量,則報錯。如果能直接賦值實例變量,則往下走
3、找相關(guān)實例變量進(jìn)行賦值
具體實現(xiàn)可移步github自定義KVC簡單實現(xiàn)





