KVO
KVO的全称是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变
假如我们有一个Person类,并且使用KVO监听age.
这时候我们发现如果我们使用
person->_age = 1;
会发现kvo监听失效
但是使用
person.age = 1;
kvo是可以实现监听的
根据两次赋值我们来深究一下kvo到底是如何实现的
前置:我们生成两个person的对象为person1和person2 并且监听person1的age属性
然后我们使用runtime来的object_getClass来显示出俩个person对象的类名 使用methodForSelector显示出setAge的方法地址 并且打印我们得到一下结果:
根据打印结果我们得知在person1未被kvo监听的情况下 两个person对象的类都是Person且setage:都是一个相同的地址.但是在person1被kvo监听后其类对象变成啦NSKVONotifying_Person 且setage也发生啦改变
由此我们得知在我们使用kvo监听的时候系统内部动态生成啦一个Person的新子类且重新的Person类的set方法(因为我们在第一次采用变量赋值时候kvo并未监听成功而采用set赋值的时候kvo监听成功)
那么kvo在动态生成的Person子类到底从写啦那些方法并且重写啦些什么东西呢?
我们使用以下方法来获得子类的相关方法名
得出结果重写啦 Person类的set:, class, dealloc, _isKVOA
那么他在重写方面的方法内部添加什么呢?
那么我们使用lldb imp得到一下结果
由此我们得出结论在kvo生成NSKVONotifying_Person内部吧setage方法替换成了_NSSetIntValueAndNotify来实现监听但是这个方法的是实现是在Foundation内部我们无法得知具体实现
根据网上一些大神的翻译解包我们大致能了解到其实内部大致是
[self willChangeValueForKey:@"age"];
[super setAge:age];
[self didChangeValueForKey:@"age"];
那么我们在Person内部重写一下这两个方法
那么其他方法是重写啦写什么呢??
我们调用person1.class方法发现打印仍然是Person类得出结果系统并不是想让你知道他动态生成啦一个子类所以重写啦class方法告诉你还是Person类
其他两个方法我并没有去验证所以不发表意见
一下是用一张图来总结一下
KVC
对于kvc我们简单用两张图可以概况 但是我们先提出一个疑问 kvc赋值kvc监听会触发吗?
答案是会的 并且就算你是变量赋值也会触发有兴趣的小伙伴可以自己去尝试一下大概实现猜想是kvc在赋值以后会主动调用willChangeValueForKey:和didChangeValueForKey:
setValue:forKey:
valueForKey