KVC可以通过 key 直接访问对象的属性,或者给对象的属性赋值,
这样可以在运行时动态的访问或者修改对象的属性
当调用 setValue: forKey: 设置属性value时,底层的执行机制如下:
1、【第一步】首先查找是否有这三种方法,按照顺序查找为:
set<Key>: 、 _set<Key> 、 setIs<Key>
a、如果有其中任意一个setter方法,则直接设置属性的value
(注意: 这里的 key 是指成员变量名,首字母大小写要符合KVC的命名规范。)
b、如果都没有,则进入【第二步】
2、【第二步】走到这一步,则查找 +(BOOL)accessInstanceVariablesDirectly 方法是否返回YES。
a、如果返回YES,则间接访问实例变量进行赋值,查找顺序为:
_<key> 、_is<key> 、 <key> 、is<key>
b、如果找到其中任意一个实例变量,则赋值。
c、如果都没有,则进入【第三步】
3、【第三步】如果setter方法或者实例变量都没有找到,
系统会执行该对象的 -(void)setValue:(id)value forUndefinedKey:(NSString *)key 方法,
默认抛出 NSUndefinedKeyException 类型的异常。
综上所属,KVC 通过 setValue: forKey: 方法设置值的流程图如下:
KVC设置值流程图.png
当调用 valueForKey: 时,底层的执行机制如下:
1、【第一步】首先查找getter方法,按照顺序查找为:
get<Key>、 <key> 、 is<Key>、_<key>
a、如果找到,则进入【第五步】
b、如果没有找到,则进入【第二步】
2、【第二步】如果没有找到 getter 方法,KVC会查找
countOf<Key> 、 objectIn<Key>AtIndex: 、 <key>AtIndexes:
a、如果找到countOf<Key>和其他两个中的任意一个,
则会创建一个响应所有 NSArray 方法的集合代理对象,并返回该对象
即 NSKeyValueArray 是 NSArray 的子类。
代理对象随后将接收到的所有 NSArray 消息
转换为 countOf<Key>、objectIn<Key>AtIndex: 、 <key>AtIndexes:消息某种组合,用来创建键值编码对象。
如果原始对象,实现了
-(void)getKey: range:(NSRange)inRange 之类的可选方法,
则代理对象也将适当时使用该方法。
b、如果没有找到组合消息,则进入【第三步】
3、【第三步】如果没有找到 上面几种方法,KVC会同时查找
countOf<Key> 、 enumeratorOf<Key> 、memberOf<Key>
a、如果方法都找到,则会创建一个响应所有 NSSet 方法的集合对象,并返回该对象
该代理对象随后将接收到的所有 NSSet 消息
转换为 countOf<Key>和enumeratorOf<Key> 和 memberOf<Key>消息某种组合,用来创建它的对象。
b、如果没有找到,则进入【第四步】
4、【第四步】走到这一步,则查找 +(BOOL)accessInstanceVariablesDirectly 方法是否返回YES。
a、如果返回YES,则依此进行搜索
_<key> 、_is<key> 、 <key> 、is<key>的实例变量
b、如果搜索到,直接获取实例变量的值,则进入【第五步】。
c、如果都没有,则进入【第六步】
5、【第五步】根据搜索到的属性值的类型,返回不同的结果。
a、如果是对象指针,则直接返回结果;
b、如果是NSNumber支持的标量类型,则将其存储在NSNumber实例中并返回它;
c、如果是NSNumber不支持的标量类型,请转换为NSValue中并返回该对象。
6、【第六步】如果上面第五步的方法均失败,
系统会执行该对象的 valueForUndefinedKey:(NSString *)key 方法,
默认抛出 NSUndefinedKeyException 类型的异常。
综上所属,KVC 通过 valueForKey: 方法设置值的流程图如下:
KVC取值流程图.png












网友评论