苹果的KVO原理通过isa-swizzling技术实现,本质实现逻辑是在runtime时添加一个子类,重写set方法进行操作,现在我们也基于runtime来实现一个KVO。

首先新建一个Person类,继承自NSObject,添加一个name属性。

然后给NSObject添加一个分类KVO,在分类中实现KVO的注册方法EZ_addObserver:forKeyPath: options:context:,这个方法的作用和系统的注册方法一样。先为Person动态添加一个子类EZKVO_Person,然后为其添加一个setName方法,因为我们要监听的是那么的变化。

  1. - (void)EZ_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
  2. // 动态添加一个类
  3. NSString *className = [@"EZKVO_" stringByAppendingString:NSStringFromClass([self class])];
  4. const char *utfName = [className UTF8String];
  5. Class myClass = objc_allocateClassPair([self class], utfName, );
  6.  
  7. // 添加setter方法
  8. class_addMethod(myClass, @selector(setName:), (IMP)setName, "v@:i");
  9.  
  10. // 注册新添加的这个类
  11. objc_registerClassPair(myClass);
  12.  
  13. // 修改被观察者的isa指针,isa指针指向Person类改为指向myclass类
  14. object_setClass(self, myClass);
  15.  
  16. // 将观察者的属性保存到当前类里面去
  17. objc_setAssociatedObject(self, (__bridge const void *)@"objc", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  18. }

上面的是注册方法,下面处理的是在更改name属性值的时候,通过重写的set方法,将消息发出给观察者让其收到键值变化。过程是先取出被观察者,然后发送消息(即observeValueForKeyPath:ofObject:change:context:)让观察者接收。当然,也可以逻辑严谨些像系统那样向父类逐层调用,这里就不写出来了。

  1. void setName(id self, SEL _cmd, id name) {
  2. // 取出观察者
  3. id objc = objc_getAssociatedObject(self, (__bridge const void *)@"objc");
  4.  
  5. // 通知观察者
  6. ((void(*)(id,SEL,id,id,id,id))objc_msgSend)(objc, @selector(observeValueForKeyPath:ofObject:change:context:), name, self, nil, nil);
  7. }

最后沿用前面两篇文章的方法,在VC里添加触摸事件改变name的值,并在消息接收方法里打印信息(方便测试,就用了keyPath来代替change保存键值)。

  1. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
  2. self.person.name = @"小明";
  3. }

消息接收

  1. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
  2. NSLog(@"name属性的改变为%@",keyPath);
  3. }

结果:2018-07-22 23:29:49.085057+0800 KVODemo[4402:212515] name属性的改变为小明

KVO的使用三:基于runtime实现KVO的更多相关文章

  1. 使用Runtime自定义KVO,原理浅析

    一.介绍 什么是KVO?全称key-value-observer,键值观察,观察者设计模式的另一种实现.其作用是通过观察者监听属性值的变化而做出函数回调. 二.原理 KVO基于Runtime机制实现, ...

  2. 《深入浅出Windows Phone 8.1 应用开发》基于Runtime框架全新升级版

    <深入浅出Windows Phone 8.1 应用开发>使用WP8.1 Runtime框架最新的API重写了上一本<深入浅出Windows Phone 8应用开发>大部分的的内 ...

  3. oc是一个全动态语言,oc的一切都是基于runtime实现的!

    oc是一个全动态语言,oc的一切都是基于runtime实现的! 从以下三方面来理解runtime吧! 1. 传统的面向过程的语言开发,例如c语言.实现c语言编译器很简单,只要按照语法规则实现一个LAL ...

  4. KVO底层实现原理,仿写KVO

    这篇文章简单介绍苹果的KVO底层是怎么实现的,自己仿照KVO的底层实现,写一个自己的KVO监听 #pragma mark--KVO底层实现 第一步:新建一个Person类继承NSObject Pers ...

  5. Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  6. word2vec原理(三) 基于Negative Sampling的模型

    word2vec原理(一) CBOW与Skip-Gram模型基础 word2vec原理(二) 基于Hierarchical Softmax的模型 word2vec原理(三) 基于Negative Sa ...

  7. [iOS]一行代码集成空白页面占位图(基于runtime+MJRefresh思想)

    2018年01月03日阅读 2472   [iOS]一行代码集成空白页面占位图(基于runtime+MJRefresh思想) LYEmptyView 此框架是本人在5,6个月前,公司启动新项目的时候, ...

  8. {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询

    Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...

  9. STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

随机推荐

  1. if-else案例–开关灯

    首先,创建一个html页面,添加一个div盒子,用css设置相应的样式,用js获取盒子的元素,通过点击事件,设置body的背景颜色,用if..else来判断当什么状态设置相应的颜色,(swith... ...

  2. Robot Framework 自动化测试 Selenium2Library 库 用法

    Robot Framework自动化测试Selenium2Library库详细用法 一.浏览器驱动   通过不同的浏览器执行脚本.   Open Browser Htpp://www.xxx.com ...

  3. Head First Python-Python中与文件相关的操作-读、处理、写

    最近在看head first python,前面也写了一些笔记,但是基本上没有涉及到一些完整的代码,现在将书中的文件相关操作的代码整理,供以后参考. 主要分为两大部分,读取文件.处理异常,处理文件.存 ...

  4. oracle_dataGuard_11G

    [李红]--切记_从库只安装实例_不需要 dbca 创建数据库 但是 netca 创建监听看个人喜欢,我反正是创建了.[DataGuard_主数据库的参数配置]1.启用 force logging 功 ...

  5. Android使用https与服务器交互的正确姿势

    HTTPS 使用 SSL 在客户端和服务器之间进行加密通信,错误地使用 SSL ,将会导致其它人能够拦截网络上的应用数据. 使用一个包含公钥及与其匹配的私钥的证书配置服务器,作为 SSL 客户端与服务 ...

  6. js中把ajax获取的数据转化成树状结构(并做成多级联动效果)

    1.首先通过ajax获取数据,此处省略,直接贴出获取到的数据格式 var arr = [{ id: 1, name: "一级标题", pid: 0 }, { id: 2, name ...

  7. 使用genism训练词向量【转载】

    转自:https://blog.csdn.net/qq_16912257/article/details/79099581 https://blog.csdn.net/thriving_fcl/art ...

  8. python迭代-如何实现反向迭代

    如何实现反向迭代 问题举例 实现一个连续浮点数发生器FloatRange,根据给定范围(start, end)和步进值(step) 产生一系列连续的浮点数,如FloatRange(3.0, 4.0, ...

  9. FB面经Prepare: Dot Product

    Conduct Dot Product of two large Vectors 1. two pointers 2. hashmap 3. 如果没有额外空间,如果一个很大,一个很小,适合scan小的 ...

  10. linux 笔记 第一天

    打开终端:ctrl+alt+t 清屏:ctrl+l 在终端在退出锁定:ctrl+c 目录:又称为文件夹,是包含所有的文件 目录创建规则: 1.大小是256 2.不能包含特殊字符 3.见名知义 路径:是 ...