KVO的实现原理
kvo的使用
// 头文件
#import "HMPerson.h"
- (void)viewDidLoad
{
[super viewDidLoad];
// 运行时机制:runtime
HMPerson *p = [[HMPerson alloc] init];
p.age = 20;
// 用KVO监听p对象age属性的改变
[p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
p.age = 30;
self.p = p;
}
// 在对象被释放的时候一定要移除监听
- (void)dealloc
{
[self.p removeObserver:self forKeyPath:@"age"];
}
/**
* 当监控的某个属性的值改变了就会调用
*
* @param keyPath 属性名(哪个属性改了?)
* @param object 哪个对象的属性被改了?
* @param change 属性的修改情况(属性原来的值、属性最新的值)
* @param context void * == id
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"%@对象的%@属性改变了:%@", object, keyPath, change);
}
KVO实现原理
利用运行时机制(runtime)系统内部会动态生成一个继承自HMPerson的子类NSKVONotifying_HMPerson。
重写HMPerson类的setAge方法:
#import "NSKVONotifying_HMPerson.h"
@implementation NSKVONotifying_HMPerson
- (void)setAge:(int)age
{
[super setAge:age];
// 通知监听器
[监听器 observeValueForKeyPath:@"age" ofObject:self change:@{} context:nil];
}
@end
每个对象内部都会有个isa指针,isa指针指向哪里,就说明对象是哪个类,就会调用哪个类的方法。
在运行时,系统会动态吧p对象的isa指针指向 NSKVONotifying_HMPerson类
[p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
所以之后再调这句代码的时候
p.age = 30;
p对象的真实类型是NSKVONotifying_HMPerson,所以会调用NSKVONotifying_HMPerson的setAge方法,重写了setAge:方法,内部又会调用super 的aetAge:方法;所以父类的setAge:也会调用。