这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战
前言
本章简单介绍下什么是KVO,如何使用KVO~
什么是KVO
KVO 是:key-value observiing 键值监听,就是可以监听键值的改变,用来监听某个对象的属性值的改变
如何使用 KVO
使用步骤:
- 确定要监听的目标
- 设置监听
- 设置监听回调
- 移除监听
1.确定监听目标
就是要确定到底要监听哪个对象的哪个属性
比如有个persion对象,对象中有个address属性,你想监听到这个对象的address属性的改变
@interface ViewController ()
@property (nonatomic, strong) Persion * persion;
@end
2.设置监听
设置监听可以使用- (**void**)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(**nullable** **void** *)context;这个方法。
这个方法有四个参数:
- observer :监听者是谁,也就是当发生改变时通知谁,调用她的
- (**void**)observeValueForKeyPath:(NSString *)keyPath ofObject:(**id**)object change:(NSDictionary<NSKeyValueChangeKey,**id**> *)change context:(**void** *)context方法,一般我们写self - keyPath :key的路径,也就是要监听的属性名称,这里就是
address - options : 监听选项,具体监听那些状态,一般都写NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld,这样就会监听到值的改变
- context: 上下文,在通知监听者时携带的上下文信息,会将这个上下文传递给监听者,也就是
- (**void**)observeValueForKeyPath:(NSString *)keyPath ofObject:(**id**)object change:(NSDictionary<NSKeyValueChangeKey,**id**> *)change context:(**void** *)context方法中的context,一般可以写nil
options 参数的全部可选值介绍:
NSKeyValueObservingOptionNew :提供属性的新值
NSKeyValueObservingOptionOld :提供属性的旧值
NSKeyValueObservingOptionInitial:设置后,在添加监听者的时候回立即通知给监听者
NSKeyValueObservingOptionPrior:设置后,每次修改属性的值时,会在值改变前,先通知一下监听者,然后改变后再通知一次
比如我们要监听persion对象的address属性可以这样写:
//设置监听
[self.persion addObserver:self forKeyPath:@"address" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"我地址变了,来找我玩呀~"];
3.设置监听回调
监听者需要实现监听回调,方便在监听到属性值改变时通知到监听者发生了改变
监听者需要实现- (**void**)observeValueForKeyPath:(NSString *)keyPath ofObject:(**id**)object change:(NSDictionary<NSKeyValueChangeKey,**id**> *)change context:(**void** *)context
这个方法有几个值传递进来:
- keyPath:发生改变的属性路径,这里就是
address - object:被监听的对象,这里就是
self.persion - change:发生改变具体的信息,里面有改变的具体值信息
- context: 上下文
上面的例子可以这样写:
//设置监听回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"收到监听 %@的%@改变了,具体信息:%@ 上下文:%@",object,keyPath,change,context);
}
例子只是做了个打印
4.移除监听
在不用的时候要及时移除监听,移除监听的方法有两个:
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
-
observer: 监听者,就是设置监听时传递的observer,一般是self
-
keyPath: 监听的属性名称,这里是
address -
context : 这个方法需要传递上下文信息,这个上下文信息就是添加监听时传递的上下文信息。
上面例子的移除监听可以这样写:
//移除监听
[self.persion removeObserver:self forKeyPath:@"address" context:@"我地址变了,来找我玩呀~"];
整个例子完整代码:
#import "ViewController.h"
#import "Persion.h"
@interface ViewController ()
@property (nonatomic, strong) Persion * persion;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.whiteColor;
self.persion = [Persion new];
self.persion.address = @"001 room";
//设置监听
[self.persion addObserver:self forKeyPath:@"address" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"我地址变了,来找我玩呀~"];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//改变属性的值
self.persion.address = @"003 room";
}
//设置监听回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"收到监听 %@的%@改变了,具体信息:%@ 上下文:%@",object,keyPath,change,context);
}
- (void)dealloc {
//移除监听
[self.persion removeObserver:self forKeyPath:@"address" context:@"我地址变了,来找我玩呀~"];
}
@end
打印结果:
收到监听 <Persion: 0x7fd816409650>的address改变了,具体信息:{
kind = 1;
new = "003 room";
old = "001 room";
} 上下文:我地址变了,来找我玩呀~