KVO
kvo 即键值观察 观察一个对象的属性的变化,并在改变时接收到事件
kvo是如何监听属性变化的呢
[self.person1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
首先要注册监听
self.person1.age = 10
当age属性变化的时候 会触发监听 收到回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
当添加addObserver:forKeyPath:options:context
时
runtime会生成一个继承与原类的中间类 NSKVONotifying_xxx
并动态修改实例对象的isa 指向这个中间类, 重写中间类的class 方法,返回原类的Class, 如果通过runtime去获取被监听实例对象的类对象,拿到的就是中间类 object_getClass()
,如果用 [person Class]
获取类对象获取到的就是原类的类对象
被监听的实例对线的中间类会重写key
的set
方法 ,调用NSSetxxxValueAndNotify
函数, 执行willChangeValueForKey
、super setter
方法修改属性的值、didChangeValueForKey
didChangeValueForKey
方法 内部会触发监听observeValueForKeyPath:ofObject:change:context:
中间类还会重写 dealloc
方法 销毁
如何关闭系统的kvo呢?
重写 +(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key 返回NO 即可
如何 手动触发kvo
手动调用willChangeValueForKey:和didChangeValueForKey:
只有执行set方法才会触发kvo,所以修改成员变量或者只修改变属性的值是不会触发kvo的,kvc例外, kvc对kvo有特殊的处理
KVC
accessInstanceVariablesDirectly 这个方法只针对所有的getter实现都没有的情况,是否可以去访问实例变量
赋值过程
按照setKey:、_setKey:顺序查找方法
如果没找到方法,并且accessInstanceVariablesDirectly返回YES,就开始查询成员变量
按照_key、_isKey、key、isKey的顺序查找成员变量
取值过程
按照getKey、key、isKey、_key的顺序查找
如果accessInstanceVariablesDirectly返回YES,就直接查询成员变量,否则直接崩溃
按照_key、_isKey、key、isKey的顺序查找成员变量
setObject: forkey 和 setValue: forKey 区别
1、setObject: forkey: 中 object 是不能够为 nil 的,不然会报错。
setValue: forKey: 中 value 能够为 nil,但是当 value 为 nil 的时候,会自动调用 removeObject: forKey:方法。
2、setValue: forKey:中 key 的参数只能够是 NSString 类型,而
setObject: forkey: 中的 key 可以是任何类型。
3、setObject: forKey: 方法是 NSMutabledictionary 特有的,setValue: forKey:方法是 KVC(键-值编码)的主要方法
网友评论