KVO的使用三:基于runtime实现KVO
苹果的KVO原理通过isa-swizzling技术实现,本质实现逻辑是在runtime时添加一个子类,重写set方法进行操作,现在我们也基于runtime来实现一个KVO。
首先新建一个Person类,继承自NSObject,添加一个name属性。
然后给NSObject添加一个分类KVO,在分类中实现KVO的注册方法EZ_addObserver:forKeyPath: options:context:,这个方法的作用和系统的注册方法一样。先为Person动态添加一个子类EZKVO_Person,然后为其添加一个setName方法,因为我们要监听的是那么的变化。
- - (void)EZ_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
- // 动态添加一个类
- NSString *className = [@"EZKVO_" stringByAppendingString:NSStringFromClass([self class])];
- const char *utfName = [className UTF8String];
- Class myClass = objc_allocateClassPair([self class], utfName, );
- // 添加setter方法
- class_addMethod(myClass, @selector(setName:), (IMP)setName, "v@:i");
- // 注册新添加的这个类
- objc_registerClassPair(myClass);
- // 修改被观察者的isa指针,isa指针指向Person类改为指向myclass类
- object_setClass(self, myClass);
- // 将观察者的属性保存到当前类里面去
- objc_setAssociatedObject(self, (__bridge const void *)@"objc", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
上面的是注册方法,下面处理的是在更改name属性值的时候,通过重写的set方法,将消息发出给观察者让其收到键值变化。过程是先取出被观察者,然后发送消息(即observeValueForKeyPath:ofObject:change:context:)让观察者接收。当然,也可以逻辑严谨些像系统那样向父类逐层调用,这里就不写出来了。
- void setName(id self, SEL _cmd, id name) {
- // 取出观察者
- id objc = objc_getAssociatedObject(self, (__bridge const void *)@"objc");
- // 通知观察者
- ((void(*)(id,SEL,id,id,id,id))objc_msgSend)(objc, @selector(observeValueForKeyPath:ofObject:change:context:), name, self, nil, nil);
- }
最后沿用前面两篇文章的方法,在VC里添加触摸事件改变name的值,并在消息接收方法里打印信息(方便测试,就用了keyPath来代替change保存键值)。
- - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
- self.person.name = @"小明";
- }
消息接收
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
- NSLog(@"name属性的改变为%@",keyPath);
- }
结果:2018-07-22 23:29:49.085057+0800 KVODemo[4402:212515] name属性的改变为小明
KVO的使用三:基于runtime实现KVO的更多相关文章
- 使用Runtime自定义KVO,原理浅析
一.介绍 什么是KVO?全称key-value-observer,键值观察,观察者设计模式的另一种实现.其作用是通过观察者监听属性值的变化而做出函数回调. 二.原理 KVO基于Runtime机制实现, ...
- 《深入浅出Windows Phone 8.1 应用开发》基于Runtime框架全新升级版
<深入浅出Windows Phone 8.1 应用开发>使用WP8.1 Runtime框架最新的API重写了上一本<深入浅出Windows Phone 8应用开发>大部分的的内 ...
- oc是一个全动态语言,oc的一切都是基于runtime实现的!
oc是一个全动态语言,oc的一切都是基于runtime实现的! 从以下三方面来理解runtime吧! 1. 传统的面向过程的语言开发,例如c语言.实现c语言编译器很简单,只要按照语法规则实现一个LAL ...
- KVO底层实现原理,仿写KVO
这篇文章简单介绍苹果的KVO底层是怎么实现的,自己仿照KVO的底层实现,写一个自己的KVO监听 #pragma mark--KVO底层实现 第一步:新建一个Person类继承NSObject Pers ...
- Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- word2vec原理(三) 基于Negative Sampling的模型
word2vec原理(一) CBOW与Skip-Gram模型基础 word2vec原理(二) 基于Hierarchical Softmax的模型 word2vec原理(三) 基于Negative Sa ...
- [iOS]一行代码集成空白页面占位图(基于runtime+MJRefresh思想)
2018年01月03日阅读 2472 [iOS]一行代码集成空白页面占位图(基于runtime+MJRefresh思想) LYEmptyView 此框架是本人在5,6个月前,公司启动新项目的时候, ...
- {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询
Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...
- STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
随机推荐
- if-else案例–开关灯
首先,创建一个html页面,添加一个div盒子,用css设置相应的样式,用js获取盒子的元素,通过点击事件,设置body的背景颜色,用if..else来判断当什么状态设置相应的颜色,(swith... ...
- Robot Framework 自动化测试 Selenium2Library 库 用法
Robot Framework自动化测试Selenium2Library库详细用法 一.浏览器驱动 通过不同的浏览器执行脚本. Open Browser Htpp://www.xxx.com ...
- Head First Python-Python中与文件相关的操作-读、处理、写
最近在看head first python,前面也写了一些笔记,但是基本上没有涉及到一些完整的代码,现在将书中的文件相关操作的代码整理,供以后参考. 主要分为两大部分,读取文件.处理异常,处理文件.存 ...
- oracle_dataGuard_11G
[李红]--切记_从库只安装实例_不需要 dbca 创建数据库 但是 netca 创建监听看个人喜欢,我反正是创建了.[DataGuard_主数据库的参数配置]1.启用 force logging 功 ...
- Android使用https与服务器交互的正确姿势
HTTPS 使用 SSL 在客户端和服务器之间进行加密通信,错误地使用 SSL ,将会导致其它人能够拦截网络上的应用数据. 使用一个包含公钥及与其匹配的私钥的证书配置服务器,作为 SSL 客户端与服务 ...
- js中把ajax获取的数据转化成树状结构(并做成多级联动效果)
1.首先通过ajax获取数据,此处省略,直接贴出获取到的数据格式 var arr = [{ id: 1, name: "一级标题", pid: 0 }, { id: 2, name ...
- 使用genism训练词向量【转载】
转自:https://blog.csdn.net/qq_16912257/article/details/79099581 https://blog.csdn.net/thriving_fcl/art ...
- python迭代-如何实现反向迭代
如何实现反向迭代 问题举例 实现一个连续浮点数发生器FloatRange,根据给定范围(start, end)和步进值(step) 产生一系列连续的浮点数,如FloatRange(3.0, 4.0, ...
- FB面经Prepare: Dot Product
Conduct Dot Product of two large Vectors 1. two pointers 2. hashmap 3. 如果没有额外空间,如果一个很大,一个很小,适合scan小的 ...
- linux 笔记 第一天
打开终端:ctrl+alt+t 清屏:ctrl+l 在终端在退出锁定:ctrl+c 目录:又称为文件夹,是包含所有的文件 目录创建规则: 1.大小是256 2.不能包含特殊字符 3.见名知义 路径:是 ...