通过前面几篇文章,我们已经了解了KVO与KVC的内部实现逻辑:
KVO通过运行时实现中间类,当被监听的值发生改变时,向观察者发送通知,告诉值已发生改变;
KVC则是通过key或keypath来改变一个值。
那么通过KVC改变的值,是否会触发KVO的监听呢?
我们今天通过代码来探讨一下。
首先,我们创建如下类:
@interface PMCar : NSObject
@property (nonatomic, copy) NSString *nioCar;
@end
@interface PMPerson : NSObject
{
@public
int _age;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) PMCar *car;
@end
实现如下:
@interface ViewController ()
{
PMPerson *_person;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_person = [[PMPerson alloc]init];
_person->_age = 19;
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld;
[_person addObserver:self forKeyPath:@"age" options:options context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"keyPath:%@-------object:%@------change:%@",keyPath,object,change);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[_person setValue:@20 forKey:@"age"];
}
当我们点击屏幕时,得到如下结果:
2019-11-24 21:43:43.264989+0800 KVC与KVO[3609:47927] keyPath:age-------object:<PMPerson: 0x600003cd50a0>------change:{
kind = 1;
new = 20;
old = 19;
}
按照之前的经验,如果我们直接修改成员变量是不会触发KVO的,但是我们通过KVC来修改成员变量时,触发了KVO监听。
我们可以理解为,在KVC改变成员变量的同时,触发了KVO操作。
那么什么操作才可以触发KVO呢?
很明显,如果手动调用- (void)willChangeValueForKey:(NSString *)key和- (void)didChangeValueForKey:(NSString *)key方法时,就会触发KVO监听。
那么事实是否如此呢,我们在PMPerson中实现这两个方法,同时打印方法调用结果,如下:
- (void)willChangeValueForKey:(NSString *)key
{
NSLog(@"%@",NSStringFromSelector(_cmd));
[super willChangeValueForKey:key];
}
- (void)didChangeValueForKey:(NSString *)key
{
NSLog(@"%@----begin",NSStringFromSelector(_cmd));
[super didChangeValueForKey:key];
NSLog(@"%@----end",NSStringFromSelector(_cmd));
}
点击屏幕,得到如下结果:
2019-11-24 21:49:23.034226+0800 KVC与KVO[3805:51657] willChangeValueForKey:
2019-11-24 21:49:23.034788+0800 KVC与KVO[3805:51657] didChangeValueForKey:----begin
2019-11-24 21:49:23.035236+0800 KVC与KVO[3805:51657] keyPath:age-------object:<PMPerson: 0x6000019592e0>------change:{
kind = 1;
new = 20;
old = 19;
}
2019-11-24 21:49:23.035450+0800 KVC与KVO[3805:51657] didChangeValueForKey:----end
结果与我们猜想的一样。
总结
当我们调用
[_person setValue:@20 forKey:@"age"];
时,系统实际做了三件事:
- 调用 willChangeValueForKey
- 调用 _person->_age = 20;修改成员变量值
- 调用 didChangeValueForKey 触发KVO操作。
以上就是KVC触发KVO的流程,如有疑问,请在评论区留言讨论。
网友评论