美文网首页
KOV的原理,自己实现KVO

KOV的原理,自己实现KVO

作者: 同窗四载 | 来源:发表于2017-07-04 17:13 被阅读0次

首先实现系统KVO

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _p = [[Person alloc]init];
    
    [_p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
    NSLog(@"%@",_p);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    _p.name = @"xxx";
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"%@",change);
}

- (void)dealloc
{
    [_p removeObserver:self forKeyPath:@"name"];
} ```
#### addObserver:forKeyPath:options:context:各个参数的作用分别是什么

/**

  1. self.person:要监听的对象
  2. 参数说明:
  • @param addObserver 观察者,负责处理监听事件的对象
  • @param forKeyPath 要监听的属性
  • @param options 观察的选项(观察新、旧值,也可以都观察)
  • @param context 上下文,用于传递数据,可以利用上下文区分不同的监听
    */
    [self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"Person Name"];

/**

  • 当监控的某个属性的值改变了就会调用
  • @param keyPath 监听的属性名
  • @param object 属性所属的对象
  • @param change 属性的修改情况(属性原来的值oldValue、属性最新的值newValue
  • @param context 传递的上下文数据,与监听的时候传递的一致,可以利用上下文区分不同的监听
    */
  • (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
    NSLog(@"%@对象的%@属性改变了:%@", object, keyPath, change);
    } ```

KVO内部实现原理

  • KVO是基于runtime机制实现的
    当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制
  • 如果原类为Person,那么生成的派生类名为NSKVONotifying_Person
派生类.png
  • 每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法
  • 键值观察通知依赖于NSObject 的两个方法:willChangeValueForKey:didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context:也会被调用。
    补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类
1429890-b28e010d3a7dbdb8.png

自己实现KVO

  • 创建NSKVONotifying_Person 继承于Person,重写属性set方法
#import "NSKVONotifying_Person.h"
#import <objc/runtime.h>

@implementation NSKVONotifying_Person

- (void)setName:(NSString *)name
{
    [super setName:name];
    
   id observer = objc_getAssociatedObject(self, @"observer");
    [observer observeValueForKeyPath:@"name" ofObject:self change:nil context:nil];
}

@end ```
- 创建一个类别 NSObject (KVO),实现自定义的添加监听的方法

import "NSObject+KVO.h"

import <objc/runtime.h>

@implementation NSObject (KVO)

  • (void)Ec_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void )context
    {
    /

    1.runtime动态生成Person的子类
    2.重写KVO_Person的属性set方法 目的:监听属性有没有变化
    3.修改对象的isa指针
    */

    //修改isa
    object_setClass(self, NSClassFromString(@"NSKVONotifying_Person"));

    //保存观察者对象
    objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }

@end ```

  • 注意:在NSObject (KVO)中要保存观察者对象,这样可以在NSKVONotifying_Person类里获取观察者对象,然后调用回执方法。

相关文章

  • KOV的原理,自己实现KVO

    首先实现系统KVO /** self.person:要监听的对象 参数说明: @param addObserver...

  • iOS高级进阶之KVO

    KVO的原理 分析原理 使用 手动调用 自己实现KVO NSObject+KVOBlock.h NSObject+...

  • iOS KVO

    KVO 示例 KVO的实现原理

  • iOS 自定义KVO

    自己实现kvo之前,需要知道iOS系统对kvo的实现。 系统实现kvo的原理 这依赖了OC强大的runtime特性...

  • iOS探索KVO实现原理,重写KVO

    写响应式编程博客时,提到了KVO,今天我们探索一下KVO的实现原理及如何自己实现KVO功能 首先简单的KVO实现 ...

  • WKWebView使用经验汇总

    1、获取加载进度: 使用KOV来观察 2、获取Title 然后重写KVO的实现方法 3、返回某个历史页面 4、清除缓存

  • 常见面试题--KVC和KVO

    1、KVO实现原理 2、KVC原理

  • 知识集锦

    https://github.com/starainDou 欢迎点星 KVO实现原理 KVO基本原理: 1 kvo...

  • iOS - 自定义KVO

    之前我们已经了解过了KVO的底层实现原理,不过呢,在我们开始实现自定义KVO之前再来简单回顾下KVO的实现原理 1...

  • iOS - KVO

    [toc] 参考 KVO KVC 【 iOS--KVO的实现原理与具体应用 】 【 IOS-详解KVO底层实现 】...

网友评论

      本文标题:KOV的原理,自己实现KVO

      本文链接:https://www.haomeiwen.com/subject/izdxhxtx.html