是什么?
Key-Value Observing (简写为KVO), 键值监听。
每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。
有什么用?
当被观察对象的属性发生改变,KVO会提供自动的消息通知。
KVO语法
被观察对象 :
- addObserver: forKeyPath: options: context:
添加观察者
观察者对象 :
- observeValueForKeyPath: ofObject: change: context:
当被观察者对象的属性发生改变,则会调用此方法。
注意:
观察者必须在被'被观察者对象'添加观察者之前,实现此方法。
KVO的联接不是两个类之间建立的,而是两个对象实例之间建立得。
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
addObserver -- 谁要监听? (self - 当前对象)
forKeyPath -- 监听什么?(监听pers对象的name属性)
options -- 当值发生改变时,传递改变之前的值NSKeyValueObservingOptionOld,
或改变之后NSKeyValueObservingOptionNew的值,
如果不知道传递什么的时候,可以用kNilOptions来代替.
context -- 传递什么,接收时就是什么.
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context;
keyPath 被更改的属性
object 被更改了属性的对象
change 监听的对象,更改前/更改后的值
context 传递什么,就是什么
示例一
[pers addObserver:self forKeyPath:@"name"
options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld
context:@"1234"];
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"谁被改了=%@,被更改了的对象是谁=%@,
改成什么样了=%@,传递什么过来=%@",
keyPath,object,change,context);
}
谁被改了=name,被更改了的对象是谁=<Person: 0x600000d502f0>,
改成什么样了={
kind = 1;
new = hhh;
old = HUH;
},传递什么过来=1234
示例二
....
HUHPerson *pers = [[HUHPerson alloc]init];
[pers setName:@"huh"];
[pers addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld context:nil];
pers.name = @"HUH";
-- KVC赋值, 等于 pers.name = @"hu";
[pers setValue:@"hu" forKey:@"name"];
....
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"更改后的值=%@,更改前的值=%@",change[NSKeyValueChangeNewKey],change[NSKeyValueChangeOldKey]);
}
打印结果
- 当
options
为NSKeyValueObservingOptionOld
的时候更改后的值=(null),更改前的值=huh 更改后的值=(null),更改前的值=HUH
- 当
options
为NSKeyValueObservingOptionNew
的时候更改后的值=HUH,更改前的值=(null) 更改后的值=hu,更改前的值=(null)
- 当
options
为kNilOptions
的时候使用 kNilOptions后,打印的结果,就是 更改后的值=(null),更改前的值=(null)
移除监听器
- removeObserver: forKeyPath:
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
-- 局部变量pers在栈里面,当跳过大括号后,局部变量会被销毁,可是当初我有给局部变量添加(KVO-监听器)
-- 对象都被销毁了,那监听器是不允许存在得,所以需要在对象销毁之前,移除监听器!
-- (原来的版本,需要手动销毁!现在的版本,不需要手动销毁,会自动移除)
-- 旧版本,手动移除监听器.
- (void)viewDidLoad {
[super viewDidLoad];
HUHPerson *pers = [[HUHPerson alloc]init];
[pers addObserver:self....]; -- 添加了KVO监听器.
[pers removeObserver:self forKeyPath:@"name"]; -- 移除监听器
}
或者在dealloc
方法里面移除监听
- (void)dealloc{
[pers removeObserver:self forKeyPath:@"name"]; -- 移除监听器
}
注意 :
KVO机制会为"被观察者"对象设置一个中间类, 此类为"被观察者对象"的子类,以NSKVONotifing_XX
命名。
KVO为什么要这么做? 查看KVO 原理
也可以看看
来自于哪里?
- iOS-MJ-UI基础-大神班/day05-KVO