一、 KVO定义
KVO
的全称是Key-Value Observing
,俗称“键值监听
”,可以用于监听某个对象属性值的改变。
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZGPerson : NSObject
@property (nonatomic, assign) int age;
@end
NS_ASSUME_NONNULL_END
#import "ZGPerson.h"
@implementation ZGPerson
@end
#import "ViewController.h"
#import "ZGPerson.h"
@interface ViewController ()
@property (nonatomic, strong) ZGPerson *person1;
@property (nonatomic, strong) ZGPerson *person2;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person1 = [ZGPerson new];
self.person1.age = 1;
self.person2 = [ZGPerson new];
self.person2.age = 2;
//给person1对象添加KVO
[self.person1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.person1.age = 11;
self.person2.age = 22;
}
//当监听对象的属性值发生改变时,就会调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"监听到%@的%@属性值发生改变了--%@",object,keyPath,change);
}
//移除监听
- (void)dealloc {
[self.person1 removeObserver:self forKeyPath:@"age"];
}
@end
二、未使用KVO监听的对象
三、使用了KVO监听的对象
四、本质分析、验证
4.1 本质分析
伪代码:
4.2 本质验证
我们看到person1
的调用内存地址发生改变,而person2
的调用内存地址并没有发生变化。
验证调用setAge:
方法时,执行了Foundation _NSSetIntValueAndNotify
方法
NSKVONotifying_ZGPerson的class对象
有自己的 NSKVONotifying_ZGPerson的meta-class对象
,NSKVONotifying_ZGPerson的class对象
的isa
指向NSKVONotifying_ZGPerson的meta-class对象
。
五、_NSSet*ValueAndNotify的内部实现
5.1 查看_NSSet*AndNotify
的存在
5.2 内部实现
调用流程:
-
调用
willChangeValueForKey:
-
调用原来的
setter实现
-
调用
didChangeValueForKey:
didChangeValueForKey:
内部会调用observer
的observeValueForKeyPath:ofObject:change:context:
方法