KVO的底層是怎么實(shí)現(xiàn)的?
1:KVO是基于Runtime機(jī)制實(shí)現(xiàn)的
2:當(dāng)某個(gè)類的對(duì)象第一次被觀察時(shí)砍鸠,系統(tǒng)就會(huì)在運(yùn)行期動(dòng)態(tài)的創(chuàng)建該類的一個(gè)派生類,在這個(gè)派生類中重寫(xiě)基類以及被觀察屬性的setter方法耕驰,派生類在被重寫(xiě)的setter方法實(shí)現(xiàn)真正的通知機(jī)制(Person->NSKVONotifying_Person)
后面我們對(duì)KVO的底層進(jìn)行一個(gè)分析
業(yè)務(wù)需求
人的年齡改變了爷辱,那么狗得知道人的年齡改變了
1:我們先新建一個(gè)項(xiàng)目
2:新建兩個(gè)類
a:一個(gè)Person類
Person 有一個(gè)age年齡屬性
b: 一個(gè)Dog類
3:我們?cè)赩iewController去實(shí)現(xiàn)點(diǎn)擊屏幕修改person的年齡屬性
#import "ViewController.h"
#import "Person.h"
#import "Dog.h"
@interface ViewController ()
@property (nonatomic, strong) Person *person;
@property (nonatomic, strong) Dog *dog;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[Person alloc]init];
self.dog = [[Dog alloc]init];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.person.age = 10;
}
@end
4:接下來(lái)再去給person增加一個(gè)方法
#import "ViewController.h"
#import "Person.h"
#import "Dog.h"
@interface ViewController ()
@property (nonatomic, strong) Person *person;
@property (nonatomic, strong) Dog *dog;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[Person alloc]init];
self.dog = [[Dog alloc]init];
//這個(gè)方法的意思是什么,就是讓self.dog知道self.person,的age改變了朦肘,也就是self.dog成為self.person的監(jiān)聽(tīng)
[self.person addObserver:self.dog forKeyPath:@"age" options:0 context:nil];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.person.age = 10;
}
@end
5:接下來(lái)我們?nèi)og類里面實(shí)現(xiàn)一個(gè)方法(注意注釋)
#import "Dog.h"
@implementation Dog
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
//這個(gè)方法什么意思饭弓?來(lái)到這里其實(shí)就是狗知道了person的年齡改變了
NSLog(@"狗知道了%@的%@改變了",object,keyPath);
}
@end
6:我們把項(xiàng)目運(yùn)行起來(lái),看是否實(shí)現(xiàn)我們的需求
可以看到媒抠,控制臺(tái)輸出了弟断,狗知道了person的age改變了
7:此時(shí)我們就簡(jiǎn)單的實(shí)現(xiàn)了我們的需求,是用的是KVO去實(shí)現(xiàn)
那KVO的底層到底是怎么實(shí)現(xiàn)的呢趴生?為什么會(huì)去調(diào)用Dog的
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
//這個(gè)方法什么意思阀趴?來(lái)到這里其實(shí)就是狗知道了person的年齡改變了
NSLog(@"狗知道了%@的%@改變了",object,keyPath);
}
8:其實(shí)是這樣,我們KVO監(jiān)聽(tīng)的屬性被改變的時(shí)候苍匆,系統(tǒng)會(huì)給我們生存一個(gè)派生類刘急,并且這個(gè)類是繼承Person類的,并且在年齡改變的時(shí)候浸踩,會(huì)重寫(xiě)屬性的setter方法
可能大家還不覺(jué)得是真的重寫(xiě)了這個(gè)類的setter方法叔汁,我給大家看一下他Person的isa指針到底是啥。