KVO的监听机制

KVO监听 是通过对对象属性setter的监听实现

  • 首先我们写个KVO 简单栗子
  • 写一个Dog类 拥有一个age属性
#import 
@interface Dog : NSObject
// 年龄
@property (nonatomic, assign) int age;
@end
  • 在控制器中监听 Dog的age属性
#import "ViewController.h"
#import "Dog.h"

@interface ViewController ()

@property (nonatomic, strong) Dog *dog;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    Dog *dog = [[Dog alloc] init];
    _dog = dog;
    
    // 监听dog的age属性
    [dog addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
    
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    
    NSLog(@"age is %d", _dog.age);
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    _dog.age++;
}

@end

此时运行程序 点击屏幕输出

此时 age值一改变 我们在监听方法中立马能知道值的变化
为了验证 KVO是通过 属性的setter方法去监听
修改下方法

直接访问成员变量
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//    _dog.age++;
    _dog-> _age++;
}

此时会报错 因为 @property 会生成私有的成员变量 将其声明为public

@interface Dog : NSObject {
    @public
    int _age;
}
//年龄
@property (nonatomic, assign) int age;

@end

此时再运行 点击屏幕 发现没有输出了

为验证是否执行了 监听方法 在监听方法里打上断点

说明 监听方法 确实执行了

从而也证明了 KVO底层是对对象属性setter 的监听

============================

继续研究KVO的原理
  • 在添加观察者之前 打上断点 观察此时dogisa指针
KVO的监听机制_第1张图片

此时dogisa指针指向它的父类 Dog

单步执行 添加完 监听者以后 再观察isa指针

KVO的监听机制_第2张图片
此时 `isa` 指针已经不再指向`Dog`   指向`NSKVONotifying_Dog`

调用 `dog`属性的`setter` 将不再去类`Dog` 中去找了  而是去类`NSKVONotifying_Dog`中找

在`NSKVONotifying_Dog`类中 重写`setter`通知观察者值的改变


修改`isa` 本质是就是修改当前对象的类名
`Class object_setClass(id object, Class cls)`

你可能感兴趣的:(KVO的监听机制)