KVO & KVC
导语:通过了浅谈系列第一篇我们可以得知,实例对象的isa指针是指向了对应类对象的,了解了这些可以非常简单的了解KVO的运作,下面就谈一下KVO是怎么实现的。
KVO(键值监听)
- KVO即键值监听,全称Key-Value Obseving,主要用于监听对象属性值得改变。
本质:KVO本质是通过创建一个类对象的子类(NSKVONotifying_类名
),并且重写了被监听属性的setter方法,达到监听的的效果。
KVO | 指针 | 若不添加KVO监听,实例对象的isa指向类对象 |
---|---|---|
实例对象(instance) | isa-> | NSKVONotifying_类名(类对象的子类) |
NSKVONotifying_类名 类对象
的结构
NSKVONotifying_类名 | 备注 |
---|---|
isa | |
superclass | 指向父类(即类对象) |
… | |
setter | 重写了被监听属性的setter方法 |
class | 重写 |
delloc | 重写 |
_isKVOA | 重写 |
- 注:
NSKVONotifying_类名
作为类对象的子类,结构相同。这个结构图不是真实结构图(isa,superclass的位置是正确的),列出的setter,class等方法,只是说明在这个子类里,这些方法都被重写了。
KVO监听实现过程
过程 |
---|
1.重写被监听属性的setter方法 |
2. 调用Foundation的_NSSetXXXValueAndNotify 函数(XXX表示属性的类型,例如_NSSetIntValueAndNotify ) |
3.调用 willChangeValueForKey -> 父类的setter -> didChangeValueForKey |
4. didChangeValueForKey内部调用observeValueForKeyPath:ofObject:change:context |
如果有手动触发KVO的需求,调用willChangeValueForKey和didChangeValueForKey就可以。KVC内部就是通过调用这两个方法触发KVO的。
KVC(键值编码)
- KVC即键值编码,全称Key-Value Coding,通过一个字符串的key访问属性,进行读写操作。
//常用API
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key;
复制代码
- KVC设值原理
KVC设值 |
---|
1.查找(按顺序) setKey, _setKey 方法, 赋值 |
2.如果没有找到以上这两个方法,查看accessInstanceVariablesDirectly方法的返回值,如果是YES,则查找(按顺序) _key, _isKey, key, isKey属性直接赋值,没有找到属性就抛出异常 |
3.如果accessInstanceVariablesDirectly方法返回值是NO,抛出异常 |
- KVC取值原理
KVC取值 |
---|
1.寻找(按顺序) getKey, key, iskey, _key 方法,取值 |
2.如果没有找到以上取值方法,查看accessInstanceVariablesDirectly 返回值,如果是YES,查找(按顺序) _key, _isKey, key, iskey属性直接取值,没有找到对应属性,抛出异常 |
3.如果accessInstanceVariablesDirectly方法返回值是NO,抛出异常 |
accessInstanceVariablesDirectly 方法是 是否直接访问实例变量 的意思
根据KVC设值和取值过程可以知道,KVC可以通过setter和getter方法设值取值,但是也不一定就是通过setter和getter设值取值,那么是如何触发KVO的呢?
其实就是通过调用willChangeValueForKey和didChangeValueForKey实现的。
注意: 如果直接访问成员变量来设值(没有通过setter,或者KVC),是无法触发KVO监听机制的。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END