KVC的全拼是Key-Value Coding,中文是键值编码。是由NSKeyValueCoding非正式协议的一种机制。政策能够直接地拜访它们的特征。这种直接拜访机制是实例变量及其相关拜访器办法供应的直接拜访的弥补。

运用KVC#### 经过key取值和设置值

//直接经过Key来取值
- (nullable id)valueForKey:(NSString *)key;苹果xs
//经过Key来设值
- (void)setValue:(nullable id)val变量名的命名规则ue forKey:(NSString *)key指针万用表的读法;

经过keyPath(路由)取值和设置值

//经过KeyPath来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;
//经过KeyPath来设值        
- (void)setValue:(nullable id)value forK指针万用表的读法eyPath:(NSString *)keyPat数组的界说h;

咱们平常项数组的界说目中首要是经过运用的是val变量的界说ueForKeyvalueForKeyPath的办法取值和设值,当然还变量的界说集结类型的一些操作能够拜见苹果KVC的文档查看运用。指针万用表的使用办法

KVC的设值进程-

setValue:f苹果13上市时刻orKey:这个办法有一个调用次序(根本数据类型):

  • 按次序查找名为 set: 或 _set 的第一个拜访器。假定找到,则运用输入值(或根据需要翻开的值)调用它数组c言语并结束。
  • 假定未找到简略拜访器,并且类办法 accessInstanceVariablesDirectly 回来 YES,则按次序查找称谓类似于 _、_is、 或 is 的实例变量。假定找到,直接运用输入值(或解包值)苹果13设置变量并结束。
  • 在未找到拜访器或实例变量时,调用 setValue:forUndefinedKey:。默许状况下,这会引发异常,但 NSObject 的子类指针万用表的使用办法可能会供应特定于键的行为。

整个流程图如下(以p数组c言语erson政策设置name特征为例):

iOS底层-KVC

KVC取值进程

和设值进程相同,取值进程valueForKey苹果手机怎样录屏:也有一个调用次序(包括集结类型):

  • 在实例中查找找到的第一个拜访器办法指针式万用表图片,其称谓类似于 get、、is 或 _,按该次序。假定找到,则调用它并运用效果持续实行进程 5。不然持续下一个进程
  • 变量之间的联系设没有找到简略的指针式万用表拜访器办法,则在实例中查找称谓与形式 c数组指针ountOf 和 objectInAtIndex:(对应于 NSArray 类界说的原始办法)和 AtI数组指针ndexes:(对应于形式)的办法N数组的界说SArray 办法 objectsAtIndexes:)。假定找到其间的第一个和至少其他两个中的一个,则创立一个集结署理政策,该政策照顾全部 NSArray 办法并回来该政策。不然,持续实行进程 3。署理政策随后将它接收到的任何 NSArray 消息转换为 countOf、objectInAtIndex: 和 AtIndexes: 消息的某种组合,并将其转换为创立它的键数组排序值编码兼容政策。假定原始政策还完结了一个可选办法,其称谓类似于 get:range:,则署理政策也会在恰当的时分运用它。实际上,署理政策与键值编码兼容政策一起作业容许底层特征表现得如同它是一个 NSArray,即使它不是。
  • 假定没有找到简略的拜访器办法或数组拜访办法组,则查找名为 countOf、enumeratorOf 和 memberOf 的变量三元组办法:(对应于 NSSet 类指针万用表的使用办法界说的原始办法)。假定找到全部三个办法,则创立一个集结署理政策,该政策照顾全部 NSSet 办法并回来该政策。不然,持续实行进程 4。这个署理政策随后将它接收到的任何 NSSet 消息转换为 countOf、enumeratorOf 和 memberOf 的某种组合:消息到创立它的变量值政策。实际上,与键值编码兼容的政策一起作业的署理政策容许底层特征表现得如同它是一个 NSSet,即使它不是。
  • 假定没有找到简数组词略的拜访器办法或集结拜访办法组,并且假定接收者的类办法accessInstanceVariables直接回来YES,则查找名为_、_is、或is的实例变量,以该次序。假定找到,直接获取实例变量的值并进行进程5,不然进行进程6。
  • 假定检索到的特征值是一个政策指针,只需回来效指针式万用表图片果即可。 假定该值是 NSNum指针万用表的使用办法b变量er 支撑的标指针c言语量类型,则将其存数组排序储在 NSNumber 实例中并数组的长度回来。 假定效果是 NSNumber 不支指针数学撑的标量类型,数组的界说则转换为 NSValue 政策并回来。苹果12
  • 假定全部其他办法都失利,请调用 valueForUndefinedKey:。默许状况下苹果x,这会引发异常,苹果官网但 NSObject 的子类可能会供应特定于键的行为。

其流程图如下:

iOS底层-KVC

自界说完结KVC

假定自己完结一个KVC能够参看上面的次序,完结valueForKeysetValueForKey指针万用表的使用办法

设值进程

  • 判别key是否为空,为空直接回来。数组的长度

  • 查找是否有 setter办法 set<Key>:_set<Key&变量泵gt;, setIs<Key>,假定有则完结并回来。

  • 假定没找到则判别accessInstan苹果xsceVariablesDirectly的回来值是否为YES,能够则往下走,不然抛变量是什么意思出异常。

  • 查找自己的ivar列表中是否包括实例变量 _变量类型有哪些&数组公式lt;k变量泵ey>, _is<Key>,&lt苹果;key>,is<Key>,找指针数组和数组指针的差异到就赋值。

  • 假定都查找不到,就抛出异常。

完结代码

- (void)js_setValue:(nullable id)value forKey:(NS苹果8plusString *)key{
// 空判别
if (key == nil || key.length == 0) {
return;
}
// 2: setter set<Key>: or _set<Key>,
// key 要大写
NSString *Key = key.capitalizedString;
// 拼接办法
NSStr数组初始化ing *setKey = [NSString stringWithFo苹果xrmat:@"set%@:",Key];
NSString *_setKey = [NSStri苹果12ng stringWithFormat:@"_set%@:",Key];
NSString *setIsKey = [NSString stringWithFormat:@"setIs%@:",Key];
if ([sel指针万用表的读法f js_performSelectorWithMethodName:setKey value:value]) {
NSLog(@"***苹果13******%@**********",setKey);
return;苹果
}else if ([self j数组公式s_perf苹果13上市时刻ormSelectorWithMethodName:_setKey value:value]) {
NSLog(数组公式@"*********%@**********",_setKey);
retur指针c言语n;
}else if ([self苹果12 js_performSelectorWithMethodName:setIsKey value:苹果12value]) {
NSLog(@"*****指针万用表的使用办法****%@*********变量*",setIsKey);
return;
}
// 3: 判别是否照顾 accessInstanceVariablesDir变量与函数ectly 回来YES NO 奔溃
// 3:判苹果8plus别是否能够直变量接赋值实例变量
if (![self.class accessInstanceVariablesDirectly] ) {
@throw [NSException exceptionWithName:@"JSUnknownKeyException" reason:[NSString stringWithFormat:@"****[%@ valueForUndefinedKey:]: thi数组初始化s class is not key v数组和链表的差异alue coding-数组公式compliant for the key name苹果8plus.****",self] userInfo:nil];
}
// 4: 直接变量数组初始化
// 获取 ivar -> 遍历 containsObjct -
/指针/ 4.1 界说一个收集实例变量的可变数组
NSMutableArray *mArray = [self getIvarListName];
// _<key> _is<Key> <key> is<K数组初始化ey数组的界说>
NSString *_key = [NSString stringWithFormat:@"_%@",key];
NSString *_isKe指针式万用表怎样读数y = [NSString stringWithF变量泵ormat:@"_is%@",Key];
NSString *isKey = [NSString stringWithFormat:@"is%@",Key];
if ([苹果xmArray containsObject:_key]) {
// 4.指针式万用表2 获取相应的 ivar
Ivar ivar = clas苹果xss_getInstanceVariable([self class], _key.UTF8String);
// 4.3 对相应的 ivar 设置值
object_setIvar(self , ivar, value);
return;
}else if ([mArray contains数组Object:_指针的拼音isKey]) {
Ivar ivar = class_g数组初始化etInstanceVariable([self class], _isKey.UTF8String);
object_setIvar(self苹果手机怎样录屏 , ivar, value);
retu变量是什么意思rn;
}else if ([mArray containsObject:key]) {
Ivar ivar = class_ge指针式万用表tIn变量的界说stanceVariable([self数组的界说 cla数组初始化ss], key.UTF8String);
object_setIvar(self , ivar变量的界说, value);
return;
}else if ([m变量是什么意思Array containsObject:isKey]) {
Ivar ivar = class_getInstanceVariab苹果手机怎样录屏le([self class], isKey.UTF8String);
object_setIvar(self , ivar, value);
retur数组n;
}
// 5:假定找不到相关实例
@throw [NSException exceptionWithName:@"JSUnknownKeyException" reason:[NSString stringWithFormat:@"****[%@ %@]: this class is not key value coding-compliant for the key name.****",self,NSStringFromSelector(_cmd)] userInfo:nil];
}

取值进程

  • 同样是判别key非空

  • 按次序查找办法:get<Key>苹果13上市时刻 <key>countOf<Key>objectIn<Key>AtIndex

  • 判别accessInstanceVariablesDirectly的回来值是否为YES,能够则往下走,不然抛变量与函数出异常。

  • 查找自己的ivar列表中苹果x是否包括实例变量 _<key&g变量名t;, _is<Key>,<key>,is<Key>,找到就取值。

  • 未找到抛出异常。

- (nu指针llable id)js_valueForKey:(NSString *)key{
// 1:判别非空
if (key ==苹果xs nil变量类型有哪些  || key.l数组词ength指针 == 0) {
return nil;
}
// 2:找到相关办法 get<Key> <key> countOf<Key>  objec变量值tIn&lt数组排序;Key指针>At变量之间的联系Index
// key 要大写
NSStr变量之间的联系ing *Key = key.capitalizedStri数组的长度ng;
// 拼接方苹果13上市时刻法
NSString *getKey = [NSString变量类型有哪些 st指针的拼音ringWithFormat:@"get%@",Key];
NSString *countOfKey = [NSString stringWithFormat:@"count变量类型有哪些Of%@",Key];
NSString *objectInKeyAtIndex = [NSString stringWithFormat:@"objectIn%@AtIndex:",Key];
#pragma cl数组指针ang diagnostic push
#pragma clang diagnostic ignored "-Warc-perfor数组词mSelector-le数组c言语aks"
if ([self res变量的界说pondsToSelector:NSSelectorFromString(getKey)]) {
return [self performSelector:NSSelectorFromString(getKey苹果xr)];
}else if ([self respond变量sToSelector:NSSelectorFromString(k苹果xsey)]){
return [self performSelector:NSSelectorFromString(key)];
}else if ([sel指针f respondsToSelector:N变量的指针其意义是指该变量的SSelectorFromString(countOfKey)]){
if ([self respondsToSelector:NSSelectorFromString(objectInKeyAtIndex)]) {
int num = (int)[self performSelector:NSSelectorFromString(countOfKey)];
NSMut变量泵ableArray *mArray = [NSM变量是什么意思utableArray arrayWithCapacity苹果手机怎样录屏:1];
for (int i = 0; i<num-1; i++) {
num = (int)[self performSelector:NSSelector苹果13FromString(countOfKey)];
}
for (int j = 0; j<num苹果xr; j++) {
id objc = [self performSelector:NSSelectorFromSt指针式万用表怎样读数ring(objectI苹果手机怎样录屏nKeyAtIndex) withObject:@(num)];
[mArray addObject:objc];
}
return mArray;
}
}
#pragma clang diagnostic pop
// 3:判别是否能够直接赋值实例变量
if (![self.class accessInstanceVariables数组指针Directly] ) {
@throw [NSException ex指针式万用表怎样读数ceptionWithN指针数组ame:@"JSUnknownKeyException" reason:[NS变量的界说String strin指针式万用表图片gWithFormat:@"***指针数学*[%@ valueForUndefinedKey:]: this class is n变量的界说ot key value coding-complian数组c言语t fo苹果13r the key name.****",self] userIn变量泵fo:nil];
}
// 4.找相关实例变量进行赋值
// 4.1 界说一个收集实例变量数组排序的可变数组
NSMutableArray *mArr指针c言语ay = [self getIvarListName];
// _<key> _is<Key&gt变量泵; <key> is<Key>
//变量值 _name -> _isName -> name -> isName
NSString *_key = [NSString stringWithFormat:@"_%@",key];
NSS指针式万用表图片tring *_isKey = [NSString stringWithFormat:@"_is%@",Key];
NSString *i变量与函数sKey = [NSString strin苹果xrgWithFormat:数组和链表的差异@"is%@",Key];
if ([mArr苹果xray containsObject:_key]) {
Iva数组排序r ivar = class_getInstanceVariable([self class], _key.UTF8String);
return object_getIvar(self, iva变量泵r);苹果官网;
}else if ([mArray containsObject:_isKey]) {
Ivar ivar = class_getInsta苹果12nceVariable([self clas指针万用表的读法s], _isKey.UTF8String);
return object_getIvar(se数组c言语lf, ivar);;
}else if ([mArray containsObje指针式万用表怎样读数ct:key]) {
Ivar ivar = class_getInstanceVariable([self class], key.UTF苹果138String);
r变量与函数eturn obj变量ect_getIvar(self, ivar);;
}else if ([mArray containsO数组指针bject:isKey苹果官网]) {
Ivar ivar = class_getInsta数组指针nceVariable([self class], isKey.UTF8String);
return object_g数组etIvar(self, ivar);;
}
return @"";
}

总结

本篇咱们首要探求了KVC的取值设值的流程。设值进程集结类型的状况没有写,感兴趣变量是什么意思的童鞋能够查看苹果官方文档进行探求。