KVO & KVC
KVO
- KVO的全称是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变
添加KVO方法
1 | self.person = [[Person alloc] init]; |
获取类的所有方法
1 | - (void)printMethodNamesOfClass:(Class)cls |
KVC
- KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性
- 常见的API有
1
2
3
4
5- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key;
示例:
1 | @interface Cat : NSObject |
setValue:forKey:的原理
- setValue:forKey:
- 按照setKey: _setKey: 顺序查找方法
- 找到方法 -> 传递参数,调用方法
- 没有找到方法 -> 查看 ==accessInstanceVariablesDirectly== 方法的返回值
- 返回 YES -> 按照 _key、_isKey、key、isKey 顺序查找==成员变量==,直接赋值,如果还是没有找到,走下一步
- 返回NO -> 调用 ==setValue:forUndefinedKey:== 并抛出异常NSUnknownKeyException
1 | @interface Person : NSObject |
valueForKey:的原理
- valueForKey:
- 按照 getKey、key、 isKey、_key 顺序查找方
- 找到方法 -> 调用方法,返回值
- 没有找到方法 -> 查看 ==accessInstanceVariablesDirectly== 方法的返回值
- 返回 YES -> 按照 _key、_isKey、key、isKey 顺序查找成员变量,直接赋值,如果还是没有找到成员变量,走下一步
- 返回NO -> 调用 调用 ==valueForUndefinedKey:== 并抛出异常NSUnknownKeyException
1 | @interface Person : NSObject |
通过KVC修改属性是否会触发KVO?
- 会触发KVO
1 | Observer *observer = [[Observer alloc] init]; |
常见问题
本质
- 利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类
- 当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数
- willChangeValueForKey:
- 父类原来的setter
- didChangeValueForKey:
- 内部会触发监听器(Oberser)的监听方法( observeValueForKeyPath:ofObject:change:context:)
手动触发KVO
- 手动调用willChangeValueForKey:和didChangeValueForKey:
直接修改成员变量会触发KVO么?
- 不会触发KVO
参考
李明杰老师课件- objc源码
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ivan's Blog!
评论









