Object-C中KVC
2019-08-01 本文已影响1人
zwwuchn
什么是KVC
KVC(Key-value coding)键值编码。iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。这样可以免去我们调用getter和setter方法,从而简化我们的代码,也可以用来修改系统控件内部属性
KVC最为重要的四个方法
- (void)setValue:(nullable id)value forKey:(NSString *)key; //通过Key来设值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; //通过KeyPath来设值
- (nullable id)valueForKey:(NSString *)key; //直接通过Key来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;
KVC使用
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end
@interface Person()
@end
----代码-----
Person *per = [[Person alloc] init];
[per setValue:@"jack" forKey:@"name"];
NSString *name = [per valueForKey:@"name"];
NSLog(@"%@", name);
打印结果:
jack
系统内部做了什么
这里我们要使用这个分类DLIntrospection
(lldb) po [object_getClass(per) instanceMethods]
<__NSArrayI 0x1005715c0>(
- (void).cxx_destruct,
- (id)name,
- (void)setName:(id)arg0
)
从上面的调试中,可以看出,使用-setValue: forKey:方法,内部调用了成员属性setter,get方法
我们来验证一下是否真的调用了成员属性setter,get方法
在Person.m文件重写setter方法
- (NSString *)name {
NSLog(@"name");
return _name;
}
- (void)setName:(NSString *)name {
NSLog(@"setName");
}
打印结果:
setName
name
所以验证了我们刚才打印出来的方法
KVC" 真 "调用流程
①.调用setValue:forKey:
> 按照顺序查找setKey、_setKey方法
验证一下:
1.1 删除 @property (nonatomic, copy) NSString *name;
1.2 在Person.m文件重写setKey、_setKey方法
- (void)setName:(NSString *)name {
NSLog(@"setName");
}
- (void)_setName:(NSString *)name {
NSLog(@"_setName");
}
打印结果:
setName
1.3 隐藏 - (void)setName:(NSString *)name 方法
打印结果:
_setName
②.如果没有找到方法
> 查看accessInstanceVariablesDirectly方法返回值
2.1 默认返回YES
2.2 如果返回NO,会抛出异常NSUnknownKeyException
③.accessInstanceVariablesDirectly方法返回YES
> 会按照_key、_isKey、key、isKey顺序查找成员变量
验证一下
3.1 在Person.m文件生成如下变量
@interface Person()
{
@public
NSString *_name;
NSString *_isName;
NSString *name;
NSString *isName;
}
@end
④.如果没有找到_key、_isKey、key、isKey成员变量,就会抛出异常,如下图

valueForKey: 的原理
①.调用valueForKey:
> 按照顺序查找getKey、key、isKey、_key方法
验证一下:
1.1 删除 @property (nonatomic, copy) NSString *name;
1.2 在Person.m文件重写getKey、key、isKey、_key方法
- (NSString *)getName {
return @"张三";
}
- (NSString *)name {
return @"李四";
}
- (NSString *)isName {
return @"王五";
}
- (NSString *)_name {
return @"小六";
}
分别注释打印结果:
张三
----
李四
----
王五
----
小六
②.如果没有找到方法
> 查看accessInstanceVariablesDirectly方法返回值
2.1 默认返回YES
2.2 如果返回NO,会抛出异常NSUnknownKeyException
③.accessInstanceVariablesDirectly方法返回YES
> 会按照_key、_isKey、key、isKey顺序查找成员变量
验证一下
3.1 在Person.m文件生成如下变量
@interface Person()
{
@public
NSString *_name;
NSString *_isName;
NSString *name;
NSString *isName;
}
@end
④.如果没有找到_key、_isKey、key、isKey成员变量,就会抛出异常,如下图
