简介
- 主角:KVO
- 全称:KeyValueObserving
- 所属:通知机制
- 形式:一对一
- 作用:允许A对象监听B对象的某个属性的改变
- 使用要求:继承自
NSObject
的对象
API和属性
- 监听方法
/// 监听方法
/// @param observer 监听对象
/// @param keyPath 被监听对象的属性
/// @param options 选项
/// @param context 其他信息
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
- 必须实现的回调方法
/// kvo回调方法
/// @param keyPath 对象的属性
/// @param object 被监听对象
/// @param change 字典 变化信息 包括 NSKeyValueChangeNewKey等key
/// @param context 额外数据
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context;
- 移除方法
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
- 使用举例
dog对象 监听 person对象的 age
的最新变化
[self.person addObserver:self.dog forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
在dog对象
的类里实现
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
NSLog(@"狗监听到%@对象的%@属性改变了",object,keyPath);
//新值
NSString *newV = change[NSKeyValueChangeNewKey];
//旧值
NSString *oldV = change[NSKeyValueChangeOldKey];
NSLog(@"newV:%@",newV);
NSLog(@"oldV:%@",oldV);
}
移除监听
[self.person removeObserver:self.dog forKeyPath:@"age"];
底层原理
KVO底层是基于runtime机制实现的
-
第一步
当A类的对象第一次被B类的对象监听时,系统就会在运行时动态给A类的对象搞一个派生类
(继承自A),类名为NSKVONotifying_A
,在NSKVONotifying_A
类中重写被B类对象监听的属性 -
第二步
系统会将A类的isa指针
会指向NSKVONotifying_A
,这时A类的对象的属性被赋值时实际上就是走的NSKVONotifying_A
类的属性的setter
方法 -
第三步
在这个setter
方法中,是这样的(借用上面人和狗的例子)
- (void)setAge:(int)age
{
[self willChangeValueForKey:@"age"];
[self setValue:age forKey:@"age"];//赋值
[self didChangeValueForKey:@"age"];
}
这里,在赋值中会走两个方法,在赋值之前调用了willChangeValueForKey
,赋值之后调用了 didChangeValueForKey
,然后调用 observeValueForKey:ofObject:change:context:
,所以B类的对象就接收到变化信息了