iOS 底层解析-----KVO与KVC原理
2019-02-28 本文已影响88人
Mr丨Yang
上文链接从isa指针看继承关系
KVO 全称Key-Value Observing,俗称"键值监听",可以用于监听某个对象属性值的改变
KVO 基本使用方法
- (void)viewDidLoad {
[super viewDidLoad];
self.person1 = [[MJPerson alloc] init];
self.person1.age = 1;
self.person1.height = 11;
self.person2 = [[MJPerson alloc] init];
self.person2.age = 2;
self.person2.height = 22;
// 给person1对象添加KVO监听
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.person1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
[self.person1 addObserver:self forKeyPath:@"height" options:options context:@"456"];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.person1.age = 20;
self.person2.age = 20;
self.person1.height = 30;
self.person2.height = 30;
}
// 当监听对象的属性值发生改变时,就会调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"监听到%@的%@属性值改变了 - %@ - %@", object, keyPath, change, context);
}
- (void)dealloc {
[self.person1 removeObserver:self forKeyPath:@"age"];
[self.person1 removeObserver:self forKeyPath:@"height"];
}
从上述代码可看出,alloc出来的person1 与 person2 实例对象,在点击屏幕的时候,只监测到了person1对象值的变化,没有监测到person2对象的变化?从代码的角度考虑是因为person2对象没有添加KVO,那么添加了KVO之后,person1实例对象在内存中发生了什么变换?
先看person2实例对象的内存调用图
未使用KVO监听.png
person1实例对象使用了KVO 那么它的内存调用图如下
使用KVO监听.pngOC在运行时的时候自动生成了一个NSKVONotifying_MJPerson 类对象作为MJPerson类对象的子类对象,通过底层C _NSSetIntValueAndNotify方法 重写了setAge:方法,进而实现KVO的过程
以下可理解为实现该过程的伪代码
#import "MJPerson.h"
@interface NSKVONotifying_MJPerson : MJPerson
@end
#import "NSKVONotifying_MJPerson.h"
@implementation NSKVONotifying_MJPerson
- (void)setAge:(int)age
{
_NSSetIntValueAndNotify();
}
// 伪代码
void _NSSetIntValueAndNotify()
{
[self willChangeValueForKey:@"age"];
[super setAge:age];
[self didChangeValueForKey:@"age"];
}
- (void)didChangeValueForKey:(NSString *)key
{
// 通知监听器,某某属性值发生了改变
[oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
@end
总结如图所示
调用过程总结.png
从上图可以看出来如果添加了KVO又不想修改属性值,那怎么主动调用监听方法呢,即可以调用以下两个方法主动去触发监听方法
[self willChangeValueForKey:@"age"];
[self didChangeValueForKey:@"age"];
KVC 全称Key-Value Coding,俗称"键值编码",可以通过一个Key来访问某个属性
KVC常用方法 (经常用到,用法不做过多解释)
//赋值
-(void)setValue:(id)value forKeyPath:(NSString *)keyPath;
-(void)setValue:(id)value forKey:(NSString *)key;
//取值
-(id)valueForKeyPath:(NSSting *)keyPath;
-(id)valueForKey:(NSSting *)key;
直接展示原理图
赋值逻辑
取值逻辑
注意:赋值,或 取值 都是有查找顺序的
问题:KVC 修改属性会触发KVO么?
会触发KVO的
因为KVC内部会实现willChangeValueForKey: didChangeValueForKey: 方法 具体笔记不再论证
下篇文章链接