美文网首页iOS 底层原理探究
KVC(四)KVC与KVO的关系

KVC(四)KVC与KVO的关系

作者: PerryMorning | 来源:发表于2019-11-24 21:56 被阅读0次

通过前面几篇文章,我们已经了解了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的流程,如有疑问,请在评论区留言讨论。

相关文章

网友评论

    本文标题:KVC(四)KVC与KVO的关系

    本文链接:https://www.haomeiwen.com/subject/gwjrwctx.html