KVC
称为:Key Value coding , 键值编码,
键值编码:由NSKeyValueCoding
非正式协议启用的一种机制,对象采用该协议间接访问其属性
。既可以通过一个 字符串key来访问某个属性
。这种间接访问机制补充了实例变量及其相关的访问器方法所提供的直接访问。
常用的API
1、 key 设值/取值
//直接通过Key来取值
- (nullable id)valueForKey:(NSString *)key;
//通过Key来设值
- (void)setValue:(nullable id)value forKey:(NSString *)key;
2、通过 keyPath (路由)设值/取值
//通过KeyPath来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;
//通过KeyPath来设值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
默认返回yes ,表示如果没有找到Set<Key>方法的话,会按照_Key 、_isKey、Key、isKey 的顺序搜索成员,设置成NO就不这样搜索了
+ (BOOL)accessInstanceVariablesDirectly;
//KVC 提供属性值正确性验证的API,他可以用来检查set的值是正确/不正确的值做一个替换值或者拒绝设置新值并返回错误原因
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回。
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//如果Key 不存在,且KVC无法搜索到任何和 Key有关的字段或者属性,则会调用这个方法,默认是抛出异常
- (nullable id)valueForUndefinedKey:(NSString *)key;
//与valueForUndefinedKey 方法一样,这个方法是设值的
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
//如果你在SetValue 方法时 给了value 传nil,则会调用这个方法
- (void)setNilValueForKey:(NSString *)key;
//输入一组Key,返回该组Key对应的value,再转成字典返回,用于将model 转到字典
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
KVC 设值的原理
日常针对对象赋值:
- 直接通过setter方法赋值
- 通过KVC键值编码的相关API赋值
LGPerson *person = [[LGPerson alloc] init];
// 1、一般setter 方法
person.name = @"hh_哈哈";
// 2、KVC方式
[person setValue:@"hh_哈哈" forKey:@"name"];
在这里,我们通过Key-Value Coding Programming Guide苹果官方文档来研究,针对设值流程,有如下说明
下面 我们针对 KVC的设值方法 : setValue forKey 来进行底层探索..
当 调用 setValue forKey; 设置属性value 时,其底层的执行流程为:
No1、 首先查找是否有这个三种 setter 方法,按照查找顺序为set<Key>: -> _set<Key> -> setIs<Key>
如果 有其中任意一个 setter 方法,则 直接设置属性的value
(注意:key是指成员变量名,首字符大小写需要符合KVC的命名规范)
如果没有,则进入 No2
No2、如果没有No1中的三个简单的setter方法,则查找accessInstanceVariablesDirectly 是否返回yes
如果返回了YES ,则查找间接访问的实例变量进行赋值,查找顺序:_<key> -> _is<key> -> <key> -> is<key>
如果找到其中任意一个实例变量,则赋值
如果都没有,则进入 No3
如果返回NO ,则进入No3
No3、 如果setter方法 或者 实例变量都没有找到,系统会执行该对象的setvalue:forUndefinedKey:方法,默认抛出 NSUndefinedKeyException类型的异常
image.pngKVC 取值的原理
根据官方文档分析KVC取值的底层原理
当调用 valueForkey: 时,执行如下:
No1、首先查找getter方法,按照get<key> -> <key> -> is<key> -> _<key> 的方法顺序查找
如果找到了 ,进入 No5
如果没有找到,进入No2
No2、如果第一步中的getter方法没有找到,KVC会查找countOf<Key> 和 objectIn <key> AtIndex: 和<key> AtIndexes:
如果找到 countOf<Key> 和其他两个中的一个,则会创建一个响应所有NSArray 方法的集合代理对象,并返回该对象,即NSKeyValueArray,是NSArray的子类。代理对象随后将接收到的所有NSArray消息 转换为 countOf<Key> ,objectIn<key> AtIndex: 和 <key>AtIndexes: 消息的某种组合,用来创建键值编码对象,如果原始对象还实现了一个名为get<key>:rang:之类的可选方法,则代理对象也将在适当时 使用该方法 (方法名的命名规则要符合KVC的标准命名方法,包括方法签名)
如果没有找到这三个访问数组的,请继续进入 No3
No3、如果没有找到上面的几种方法,则会同时查找countOf <Key>,enumeratorOf<Key> 和memberOf<Key> 这三个方法
如果这三个方法都找到了,则会创建一个响应 所有NSSet 方法的集合代理对象,并返回该对象,此代理对象随后将其收到的所有 NSSet 消息 转换为 countOf<Key>,enumeratorOf<key> 和 memberOf<Key>: 消息的某种组合,用于创建他的对象
如果还没有找到,则进入 No4
No4、如果还没有找到,检查类方法InstanceVariablesDirectly 是否YES,依次搜索_<key>、_is<key>、<key>、 is<key> 的实例变量
如果搜到,直接获取实例变量的值,进入No5
No5、根据搜索到的 属性值的类型,返回不同的结果
如果是对象指针,则直接返回结果
如果是NSNumber的标量类型,则将其 存储在NSNumber实例中并返回它
如果是NSNumber不支持的标量类型,请转换为NSValue对象 并返回该对象
网友评论