你以为的并不是你以为的
1-1KVO原理.png
一 基本使用
KVO: key-value observing
//Person
@interface Person : NSObject
@property (nonatomic, assign) int age;
@end
implementation Person
@end
//VC
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@property (nonatomic, strong) Person *person1;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person1 = [[Person alloc] init];
self.person1.age = 1;
NSKeyValueObservingOptions options = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
[self.person1 addObserver:self forKeyPath:@"age" options:options context:nil];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.person2.age = 20;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"监听到:%@的%@:属性的值发生了改变:%@",keyPath,object,change);
}
//移除监听。
- (void)dealloc {
[self.person1 removeObserver:self forKeyPath:@"age"];
}
二 KVO本质
利用Runtime动态生成一个子类 NSKVONotify_xxxxxx
重写子类的setter方法。
从两个方法可以证明对一个对象添加KVO监听之后,KVO内部实现会创建一个新的子类NSKVONotify_xxxxx
eg1:自己创建一个继承自Person的子类 NSKVONotify_Person 什么不做。运行程序。控制他打印如下信息:KVO不起作用了。
KVO failed to allocate class pair for name NSKVONotifying_Person, automatic key-value observing will not work for this class
1-2-KVONotWorkForThisClass.png
eg2:打印一下实例对象的isa指针
//KVO监听的实例对象的isa指针
p self.person1.isa
(Class) $0 = NSKVONotifying_Person
//未进行KVO监听的实例对象的isa指针
p self.person2->isa
(Class) $7 = Person
1-3添加KVO监听之后的isa.png
2-1猜测KVO内部实现
苹果不开源,只能靠猜。
kvo 实现原理,给Person对象添加KVO监听为例
1.利用runtime函数动态创建一个继承制Person的子类NSKVONotifying_Person。
2.重写setter方法。(NSKVONotifying_Person 重写了父类Person的setAag:方法 ,
在setter方法内部调用Foundation框架的 _NSSetIntValueAndNotify() 这个函数
3.这个函数 内部做了以下操作
3-1 调用 willChangeValueForKey:方法 ✅
3-2 调用父类的setter方法。
3-3 调用 didChangeValueForKey: 方法 ✅
3-3-1 该方法内部调用了 observeValueForKeyPath: ofObject: change: context: 通知监听器,xxxx属性值发生了改变。
//伪代码
@implementation NSKVONotifying_Person
- (void)setAge:(int)age {
_NSSetIntValueAndNotify();
}
//伪代码
void _NSSetIntValueAndNotify()
{
[self willChangeValueForKey:@"age"];
[super setAge:age];
[self didChangeValueForKey:@"age"];
}
- (void)didChnageValueForKey:(NSString *)key {
//通知监听器,某某属性值发生了改变。
[observer observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
@end
用图形来描述就是:
1-4NSKVONotifying的内部实现.png
关于 _NSSetIntValueAndNotify() 函数,可以使用runtime提供的函数 && LLDB指令来查看。
1-5关于_NSSetIntValueAndNotify.png
三 题
1.kvo 的实现原理?(本质?)
1.使用runtime动态生成一个子类 NSKVONotifying_xxxxx ,并让instance对象的isa指向这个全新的子类。
2.该子类重写了父类的setter方法,当修改instance对象的属性时,会调用Foundation框架的 _NSSetXXXXValueAndNotify() 函数,该函数内部做了以下操作
2-1.调用 willChangeValueForKey:
2-2 调用父类的 setter方法
2-3 调用 didChangeValueForKey: ✅
2-3-1:didChangeValueForKey ✅方法内部会触发监听器的(observer) 监听方法( observeValueForKeyPath:ofObject:change:context)
2.手动触发KVO?
手动调用 这两个方法
willChangeValueForKey: ✅
didChangeValueForKey: ✅
3.修改成员变量会触发KVO?
NO
网友评论