前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ios KVO及实现原理

ios KVO及实现原理

作者头像
赵哥窟
发布2018-09-13 11:42:37
6370
发布2018-09-13 11:42:37
举报
文章被收录于专栏:日常技术分享日常技术分享

概述 KVO全称KeyValueObserving,是苹果提供的一套事件通知机制。允许对象监听另一个对象特定属性的改变,并在改变时接收到事件。由于KVO的实现机制,所以对属性才会发生作用,一般继承自NSObject的对象都默认支持KVO。

KVO和NSNotificationCenter都是iOS中观察者模式的一种实现。区别在于,相对于被观察者和观察者之间的关系,KVO是一对一的,而不一对多的。KVO对被监听对象无侵入性,不需要修改其内部代码即可实现监听。

KVO可以监听单个属性的变化,也可以监听集合对象的变化。通过KVC的mutableArrayValueForKey:等方法获得代理对象,当代理对象的内部对象发生改变时,会回调KVO监听的方法。集合对象包含NSArray和NSSet。

基础使用 使用KVO分为三个步骤: 1.注册观察者,指定被观察对象的属性

代码语言:javascript
复制
 [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

2.在观察者中实现以下回调方法

代码语言:javascript
复制
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"%@",change);
}

3.当观察者不需要监听时

代码语言:javascript
复制
 [person removeObserver:self forKeyPath:@"name"];

实现原理 KVO是通过isa-swizzling技术实现的。在运行时根据原类创建一个中间类,这个中间类是原类的子类,并动态修改当前对象的isa指向中间类。并且将class方法重写,返回原类的Class。

测试代码

代码语言:javascript
复制
Person *person = [Person new];
person.name = @"old";
NSLog(@"before Class Name:%s",object_getClassName(person));
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
 NSLog(@"after Class Name:%s",object_getClassName(person));

控制台输出

代码语言:javascript
复制
2018-09-04 09:59:09.531941+0800 KOVAndKVCDemo[36344:19883033] before Class Name:Person
2018-09-04 09:59:09.532317+0800 KOVAndKVCDemo[36344:19883033] after Class Name:NSKVONotifying_Person

上面的原理结合代码原理可以这样理解: 当观察对象Person时,KVO机制动态创建一个新的名为: NSKVONotifying_Person的新类,该类继承自对象Person的本类,且KVO为NSKVONotifying_Person重写观察属性的setter 方法,setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象属性值的更改情况。

怎么理解setter 方法会负责在调用原 setter 方法之前和之后,类似看如下代码

代码语言:javascript
复制
-(void)setName:(NSString *)name
{
    [self willChangeValueForKey:@"name"];    //KVO在调用存取方法之前总调用
    [super name forKey:@"name"]; //调用父类的存取方法
    [self didChangeValueForKey:@"name"];     //KVO在调用存取方法之后总调用
}

NSKVONotifying_Person类剖析 在这个过程,被观察对象的 isa 指针从指向原来的Person类,被KVO机制修改为指向系统新创建的子类NSKVONotifying_Person类,来实现当前类属性值改变的监听;

子类setter方法剖析 KVO的键值观察通知依赖于 NSObject 的两个方法:willChangeValueForKey:和 didChangevlueForKey:,在存取数值的前后分别调用2个方法: 被观察属性发生改变之前,willChangeValueForKey:被调用,通知系统该 keyPath 的属性值即将变更;当改变发生后, didChangeValueForKey: 被调用,通知系统该 keyPath 的属性值已经变更;之后, observeValueForKey:ofObject:change:context: 也会被调用。且重写观察属性的setter 方法这种继承方式的注入是在运行时而不是编译时实现的。

如何手动实现KVC?

代码语言:javascript
复制
 [person willChangeValueForKey:@"name"];
  person.name = @"Alex";
 [person didChangeValueForKey:@"name"];

demo:https://github.com/destinyzhao/KOVAndKVCDemo

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.09.04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档