探索底層原理,積累從點(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我們給Person對象的
age屬性進(jìn)行了賦值和取值的操作,同時(shí)還使用setValue: forKeyPath:方法做了一下相對復(fù)雜的Person對象中student的height屬性做了賦值和取值。其中Person和Student的關(guān)系如下:
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、_isKey、key、isKey這四個(gè)成員變量,如果找到其中某個(gè)成員變量,完成賦值。如果四個(gè)成員變量全部未找到,那么會(huì)調(diào)用setValue:forUndefinedKey:方法,并拋出異常NSUnknownKeyException的異常,賦值失敗。
值得注意的是,accessInstanceVariablesDirectly方法返回值默認(rèn)是YES。
我們用流程圖總結(jié)如下:

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

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