有关KVO (Key-Value Observing)大家一定不会觉得陌生,常常被用来监听某个对象属性值的改变。那么有关底层实现原理是需要来探讨的,今天就来说说KVO的基本使用以及实现原理。

什么是KVO

KVO (Key-Value Observing) 是 Objective-C 对观察者模式(Observer Pattern)的实现。当被观察者对象的某个被观察属性发生变化时,观察者对象会获得通知。

苹果官方文档中对KVO的定义是

Automatic key-value observing is implemented using a technique called isa-swizzling. The isa pointer, as the name suggests, points to the object's class which maintains a dispatch table. This dispatch table essentially contains pointers to the methods the class implements, among other data. When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance. You should never rely on the isa pointer to determine class membership. Instead, you should use the class method to determine the class of an object instance.

从中可以看到并不想我们想象的那么简单,KVO的实现中使用了黑魔法 isa-swizzling,后面将描述其实现过程。

下面先来看KVO的基本使用。

KVO的基本使用

以下使用官方文档中的Example为例(官方文档)。

创建两个类,Person类和Account类。假使一个Person对象拥有一个Account对象,代表一个人在银行的储蓄账号。这样,当银行的收益和利率变化时这个人必须时刻注意到。在Account类中添加两个公共属性,如图所示:

既然Account类的属性是公共的,Person对象可以通过轮询查找来获取Account属性值的变化,但显然这样效率低下。

1、为Person对象添加监听对象,调用方法:addObserver:forKeyPath:options:context:。

2、在Person类中实现observeValueForKeyPath:ofObject:change:context:方法。这样,当Account属性值发生变化时就会调用此方法,将其值的变化通知过来。

3、最后,当不再希望收到通知时一定要在Person类销毁时注销通知,调用removeObserver:forKeyPath:方法。

实现原理

KVO是基于Runtime实现的,其实现过程 ChenYilong (微博@iOS程序犭袁)在下面这张图中画的很明白。

当观察一个对象的时候,运行期系统会动态创建一个新的类。

这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法。重写的 setter 方法会负责在调用原 setter 方法之前和之后(被观察属性发生改变之前 willChangeValueForKey:方法会被调,被观察的属性发生改变之后didChangeValueForKey:方法则会被调用),通知所有观察对象:值的更改。

最后通过 isa 混写(isa-swizzling) 把这个对象的 isa 指针 ( isa 指针告诉 Runtime 系统这个对象的类是什么 ) 指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。

感谢 ChenYilong 在《《招聘一个靠谱的 iOS》—参考答案(下)》中的精彩答案,节省了我很多时间去研究KVO的实现细节。

手写KVO

这里推荐Glow 技术团队博客上的一篇文章《如何自己动手实现 KVO》,文章里关于KVO实现细节是我在网上看到最全的,而且附带源码。感兴趣的同学可以去看看。这里就不浪费空间贴大量代码了。

KVO的不足

KVO一度被认为是非常不好的API,比如其 以字符串作为关键字、remove observer不当会导致crash,《Key-Value Observing Done Right》、《KVO Considered Harmful》以及Mattt Thompson在《Key-Value Observing》中都强调了KVO的不足之处,有兴趣可以去看下。

参考文章

kvo实现原理_KVO实现原理相关推荐

  1. grpc通信原理_容器原理架构详解(全)

    目录 1 容器原理架构 1.1 容器与虚拟化 1.2 容器应用架构 1.3 容器引擎架构 1.4 Namespace与Cgroups 1.5 容器镜像原理 2 K8S原理架构 2.1 K8S主要功能 ...

  2. BC之SC:区块链之智能合约——与传统合约的比较以及智能合约模型部署原理、运行原理相关配图

    BC之SC:区块链之智能合约--与传统合约的比较以及智能合约模型部署原理.运行原理相关配图 目录 SC与传统合约的比较 SC模型部署原理.运行原理 SC与传统合约的比较 1.传统合约VS智能合约  特 ...

  3. 真香定律!Android动态换肤实现原理解析,原理+实战+视频+源码

    自己项目中一直都是用的开源的xUtils框架,包括BitmapUtils.DbUtils.ViewUtils和HttpUtils四大模块,这四大模块都是项目中比较常用的.最近决定研究一下xUtils的 ...

  4. mapreduce原理_Hbase Bulkload 原理面试必备

    当需要大批量的向Hbase导入数据时,我们可以使用Hbase Bulkload的方式,这种方式是先生成Hbase的底层存储文件 HFile,然后直接将这些 HFile 移动到Hbase的存储目录下.它 ...

  5. kafka分区与分组原理_Kafka工作原理

    Kafka工作原理 Kafka工作原理 4.1. topic和消息 4.2. Producer 4.3. Consumer 4.4. Kafka核心特性 4.5. consumer.consumer ...

  6. 【重难点】【JUC 04】synchronized 原理、ReentrantLock 原理、synchronized 和 Lock 的对比、CAS 无锁原理

    [重难点][JUC 04]synchronized 原理.ReentrantLock 原理.synchronized 和 Lock 的对比.CAS 无锁原理 文章目录 [重难点][JUC 04]syn ...

  7. bootloader功能介绍/时钟初始化设置/串口工作原理/内存工作原理/NandFlash工作原理...

    bootloader功能介绍 初始化开发板上主要硬件(时钟,内存,硬盘), 把操作系统从硬盘拷贝到内存,然后让cpu跳转到内存中执行操作系统. boot阶段 1.关闭影响CPU正常执行的外设 -关闭看 ...

  8. TRIZ系列-创新原理-14~15-曲面化原理和动态性原理

    一.曲面化原理的表述如下 1)用曲线部件代替直线部件,用球面代替平面,用球体代替立方体: 2)采用滚筒,球体,螺旋体: 3)利用离心力,用旋转物体代替直线运动 由于TRIZ的创新原理是基于专利分析的基 ...

  9. 分类计数原理与分步计数原理_分类计数原理与分步计数原理

    分类计数原理与分步计数原理 <分类计数原理与分步计数原理 ( 一 ) >教学设计 柳州地区民族高级中学 覃艳莉 相关教材 : 人民教育出版社的全日制普通高级中学教科书 ( 必修 ) < ...

最新文章

  1. R语言基础知识详解及概括
  2. 达特茅斯计算机专业师资力量如何,达特茅斯学院计算机科学computer science专业排名第126~150名(2020THE泰晤士高等教育世界大学排名)...
  3. spring11:为应用指定多个spring配置文件
  4. 以MATLAB的方式实现微积分问题的计算机求解问题及解决方案集锦(二)
  5. cmake教程(为什么要用cmake?)(cmake编译opencv)(就是个跨平台的编译工具Linux、windows)(很重要,必须得学)(报错解决方案)opencv编译
  6. python shelve模块_python常用模块之shelve模块
  7. 性能测试关注点整理总结!
  8. ABP框架搭建项目系列教程基础版
  9. ai的预览模式切换_ai预览快捷键是什么,Adobe Illustrator预览快捷键是什么?
  10. cpu使用率100%,内存占用不足30%,system进程 pId=4
  11. oracle 创建cdb,Oracle 12C -- 手动创建CDB
  12. 编译原理 LL1文法的判断和句子识别
  13. 玩一玩Google涂鸦中的《吃豆人》
  14. 助你成功的10个万能谈话技巧
  15. 计算机是指能根据给定程序自动,001第1章 计算机基础.ppt
  16. 分享:虚拟筛选常用化合物库
  17. kafka cpu占用高
  18. R语言利用igraph和networkD3包快速入门做出炫酷的社交网络图等几类图。
  19. 怎样营造更好的职场氛围?
  20. 干货 | 每天上百万通话,携程电话系统性能测试实践

热门文章

  1. ubuntu怎么添加中文输入法
  2. L9170 LGCN 原厂直销5A大电流输出DC双向马达驱动电路IC
  3. [转载]Struts Web开发框架WebPage3
  4. 49股权与51股权的区别有哪些
  5. java学习笔记 多线程(一)创建多线程,线程常用方法
  6. 课程设计——学生成绩管理系统 C语言
  7. Java8几种常用字符串拼接方法总结
  8. WHR-HP-G54
  9. 苹果支付(Apple Pay) 接口文档地址
  10. 鲸探发布点评:7月21日发售辟邪、唐风汉韵、马首圣银壶数字藏品