通過(guò)前面幾篇文章,我們已經(jīng)了解了KVO與KVC的內(nèi)部實(shí)現(xiàn)邏輯:
KVO通過(guò)運(yùn)行時(shí)實(shí)現(xiàn)中間類,當(dāng)被監(jiān)聽(tīng)的值發(fā)生改變時(shí)闷哆,向觀察者發(fā)送通知抱怔,告訴值已發(fā)生改變屈留;
KVC則是通過(guò)key或keypath來(lái)改變一個(gè)值灌危。
那么通過(guò)KVC改變的值勇蝙,是否會(huì)觸發(fā)KVO的監(jiān)聽(tīng)呢味混?
我們今天通過(guò)代碼來(lái)探討一下蔓挖。
首先瘟判,我們創(chuàng)建如下類:
@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
實(shí)現(xiàn)如下:
@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"];
}
當(dāng)我們點(diǎn)擊屏幕時(shí),得到如下結(jié)果:
2019-11-24 21:43:43.264989+0800 KVC與KVO[3609:47927] keyPath:age-------object:<PMPerson: 0x600003cd50a0>------change:{
kind = 1;
new = 20;
old = 19;
}
按照之前的經(jīng)驗(yàn)刀诬,如果我們直接修改成員變量是不會(huì)觸發(fā)KVO的陕壹,但是我們通過(guò)KVC來(lái)修改成員變量時(shí)糠馆,觸發(fā)了KVO監(jiān)聽(tīng)九昧。
我們可以理解為铸鹰,在KVC改變成員變量的同時(shí)蹋笼,觸發(fā)了KVO操作剖毯。
那么什么操作才可以觸發(fā)KVO呢?
很明顯涣狗,如果手動(dòng)調(diào)用- (void)willChangeValueForKey:(NSString *)key和- (void)didChangeValueForKey:(NSString *)key方法時(shí)镀钓,就會(huì)觸發(fā)KVO監(jiān)聽(tīng)。
那么事實(shí)是否如此呢窟赏,我們?cè)赑MPerson中實(shí)現(xiàn)這兩個(gè)方法涯穷,同時(shí)打印方法調(diào)用結(jié)果,如下:
- (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));
}
點(diǎn)擊屏幕,得到如下結(jié)果:
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
結(jié)果與我們猜想的一樣。
總結(jié)
當(dāng)我們調(diào)用
[_person setValue:@20 forKey:@"age"];
時(shí)揽咕,系統(tǒng)實(shí)際做了三件事:
- 調(diào)用 willChangeValueForKey
- 調(diào)用 _person->_age = 20舔涎;修改成員變量值
- 調(diào)用 didChangeValueForKey 觸發(fā)KVO操作。
以上就是KVC觸發(fā)KVO的流程掘而,如有疑問(wèn),請(qǐng)?jiān)谠u(píng)論區(qū)留言討論于购。