黑马程序员技术交流社区

标题: KVO的底层是怎么实现的? [打印本页]

作者: 老旭谈IT    时间: 2017-12-6 14:43
标题: KVO的底层是怎么实现的?
本帖最后由 老旭谈IT 于 2017-12-6 15:05 编辑

KVO的底层是怎么实现的?
1:KVO是基于Runtime机制实现的
2:当某个类的对象第一次被观察时,系统就会在运行期动态的创建该类的一个派生类,在这个派生类中重写基类以及被观察属性的setter方法,派生类在被重写的setter方法实现真正的通知机制(Person->NSKVONotifying_Person)
后面我们对KVO的底层进行一个分析业务需求
人的年龄改变了,那么狗得知道人的年龄改变了
1:我们先新建一个项目



屏幕快照 2016-04-21 上午10.55.38.png

2:新建两个类
a:一个Person类
Person 有一个age年龄属性
b: 一个Dog类



屏幕快照 2016-04-21 上午10.58.44.png

3:我们在ViewController去实现点击屏幕修改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:接下来再去给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];    //这个方法的意思是什么,就是让self.dog知道self.person,的age改变了,也就是self.dog成为self.person的监听    [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:接下来我们去Dog类里面实现一个方法(注意注释)
#import "Dog.h"@implementation Dog-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{        //这个方法什么意思?来到这里其实就是狗知道了person的年龄改变了    NSLog(@"狗知道了%@的%@改变了",object,keyPath);}@end
6:我们把项目运行起来,看是否实现我们的需求



屏幕快照 2016-04-21 上午11.21.43.png

可以看到,控制台输出了,狗知道了person的age改变了
7:此时我们就简单的实现了我们的需求,是用的是KVO去实现
那KVO的底层到底是怎么实现的呢?为什么会去调用Dog的
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{        //这个方法什么意思?来到这里其实就是狗知道了person的年龄改变了    NSLog(@"狗知道了%@的%@改变了",object,keyPath);}
8:其实是这样,我们KVO监听的属性被改变的时候,系统会给我们生存一个派生类,并且这个类是继承Person类的,并且在年龄改变的时候,会重写属性的setter方法



屏幕快照 2016-04-21 上午11.26.56.png


可能大家还不觉得是真的重写了这个类的setter方法,我给大家看一下他Person的isa指针到底是啥。










欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2