KVC原理分析

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)分析
image.png

以上文檔大致的意思是:
對象從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,修改其中第一個元素的值:

image.png

第三種:
array取值
image.png

聚合操作符
image.png

image.png

第四種:可以操作結(jié)構(gòu)體
定義一個結(jié)構(gòu)體

typedef struct {
    float x, y, z;
} ThreeFloats;

賦值和調(diào)用


image.png

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


image.png

二、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
image.png
image.png

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

image.png
  • 再分析一下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)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容