iOS底層原理探索—KVC的本質(zhì)

探索底層原理,積累從點(diǎn)滴做起。大家好,我是Mars。

往期回顧

iOS底層原理探索—OC對象的本質(zhì)
iOS底層原理探索—class的本質(zhì)
iOS底層原理探索—KVO的本質(zhì)
今天帶領(lǐng)大家探索iOS之KVC的本質(zhì)。

KVC

KVC全稱是Key-Value Coding,鍵值編碼,可以通過Key來訪問和修改屬性。
KVC常用的API包括:

//存值
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
//取值
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key; 

KVC的使用

下面我們簡單使用一下KVC:

KVC簡單使用.png

通過代碼可以看到,通過KVC我們給Person對象的age屬性進(jìn)行了賦值和取值的操作,同時(shí)還使用setValue: forKeyPath:方法做了一下相對復(fù)雜的Person對象中student的height屬性做了賦值和取值。其中Person和Student的關(guān)系如下:
KVC簡單使用1.png

setValue:forKey:只是根據(jù)屬性名做賦值和取值的操作,而setValue: forKeyPath:方法則能根據(jù)key的路徑做一些層級間的復(fù)雜訪問操作。

KVC底層原理

KVC賦值

KVC賦值的底層原理就是,當(dāng)我們調(diào)用setValue: forKeyPath:方法后,系統(tǒng)會(huì)按照順序查找兩個(gè)方法:setKey_setKey,如果實(shí)現(xiàn)了這兩個(gè)方法其中一個(gè),那么就會(huì)傳遞參數(shù),并且調(diào)用實(shí)現(xiàn)的方法。我們驗(yàn)證一下:
我們通過代碼來設(shè)置Person的age屬性,并且在Person類里面依次分別實(shí)現(xiàn)setAge_setAge兩個(gè)方法

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        Person *person = [[Person alloc] init];
        // 通過KVC修改age屬性
        [person setValue:@10 forKey:@"age"];

        
    }
    return 0;
}

Person類.m文件中的實(shí)現(xiàn):

#import "Person.h"

@implementation Person
- (void)setAge:(int)age
{
    NSLog(@"setAge: - %d", age);
}

//- (void)_setAge:(int)age
//{
//    NSLog(@"_setAge: - %d", age);
//}
@end

第一次測試我們先注釋掉_setAge方法,打印輸出

setAge:- 10

第二次測試我們注釋掉setAge方法,去掉_setAge的注釋:

#import "Person.h"

@implementation Person
//- (void)setAge:(int)age
//{
//    NSLog(@"setAge: - %d", age);
//}

- (void)_setAge:(int)age
{
    NSLog(@"_setAge: - %d", age);
}
@end

打印輸出

_setAge: - 10

第三次測試我們將注釋全部去掉:

#import "Person.h"

@implementation Person
- (void)setAge:(int)age
{
    NSLog(@"setAge: - %d", age);
}

- (void)_setAge:(int)age
{
    NSLog(@"_setAge: - %d", age);
}
@end

打印輸出

setAge:- 10

通過測試我們可以驗(yàn)證我們上面的結(jié)論。
如果沒有實(shí)現(xiàn)setKey_setKey這兩個(gè)方法的話,會(huì)繼續(xù)調(diào)用accessInstanceVariablesDirectly方法,這個(gè)方法的返回值是BOOL類型,;如果返回值是NO,那么會(huì)調(diào)用setValue:forUndefinedKey:方法,并拋出異常NSUnknownKeyException的異常,賦值失敗。如果返回值是YES,那么會(huì)繼續(xù)按照順序依次查找按照_key、_isKeykey、isKey這四個(gè)成員變量,如果找到其中某個(gè)成員變量,完成賦值。如果四個(gè)成員變量全部未找到,那么會(huì)調(diào)用setValue:forUndefinedKey:方法,并拋出異常NSUnknownKeyException的異常,賦值失敗。
值得注意的是,accessInstanceVariablesDirectly方法返回值默認(rèn)是YES。

我們用流程圖總結(jié)如下:


KVC賦值流程.png

KVC取值

KVC取值流程和賦值流程一樣,我們直接用流程圖總結(jié)一下:


KVC取值流程圖.png

關(guān)于KVC的底層原理探索我們告一段落,如有疑問,歡迎在評論區(qū)留言。

iOS進(jìn)階


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

相關(guān)閱讀更多精彩內(nèi)容

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