苹果的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的更多相关文章

  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. python2和python3共存时,设置默认python为python3

    sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 100 sudo update-alternati ...

  2. 转:彻底搞清楚javascript中的require、import和export

    原文地址:彻底搞清楚javascript中的require.import和export   为什么有模块概念 理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块. 但是,Ja ...

  3. JMeter 压测基础(四)——Java工程测试

    JMeter Java工程测试 1.eclipse中新建工程 2.导入需要的jar包 从JMeter安装目录lib/ext中两个jar包buildPath到Java project中,分别是“Apac ...

  4. python 包下载地址

    https://www.lfd.uci.edu/~gohlke/pythonlibs/

  5. VisualStudioCode创建的asp.net core项目部署到IIS,以及遇到的问题

    一.发布项目 在visual studio code中通过命令“dotnet publish”,如下图: 这里我把发布位置设置到了D:\WebSite\netcoredemo下. 二.设置IIS 0. ...

  6. css实现三角形相关

    1.css样式面包屑导航条实现矩形和三角箭头拼接 .cssTest { font-family: PingFangSC-Regular; font-size: 16px; color: #333333 ...

  7. 加壳软件-Virbox Protector Standalone

    Virbox Protector Standalone 加壳工具 防止代码反编译,更安全,更方便 产品简介 Virbox Protector Standalone提供了强大的代码虚拟化.高级混淆与智能 ...

  8. 3.2.3 SpringMVC注解式开发

    SpringMVC注解式开发 1. 搭建环境 (1) 后端控制器无需实现接口 , 添加相应注解 Controller类添加注解 @Controller //该注解表将当前类交给spring容器管理 @ ...

  9. Linux的top命令学习【转载】

    转自:https://blog.csdn.net/sanshiqiduer/article/details/1933625 1.top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的 ...

  10. 个人常用的移动端浅灰底index.html

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...