当前位置: 首页 > news >正文

深入理解 KVO

在 iOS 中,KVO(Key-Value Observing)是一个强大的观察机制,它的底层实现相对复杂。KVO 利用 Objective-C 的动态特性,为对象的属性提供观察能力。

KVO 的底层实现

1. 动态子类化

当一个对象的属性被添加观察者时,KVO 会在运行时动态地创建该对象的子类,并重写该属性的 setter 方法。

  1. 动态创建子类:KVO 会创建一个新的类,这个新类是被观察对象的子类,通常这个类的名字是 _NSKVOClassName_ClassName 形式。
  2. 重写 setter 方法:在这个动态创建的子类中,KVO 会重写被观察属性的 setter 方法。

2. 重写 setter 方法

重写后的 setter 方法在属性值发生变化时,会进行以下操作:

  1. 触发 willChangeValue(forKey:):通知即将发生变化。
  2. 调用原始 setter 方法:通过消息转发机制调用原始的 setter 方法,以实际更新属性值。
  3. 触发 didChangeValue(forKey:):通知变化已经发生,触发观察者回调。

3. 动态方法解析

在 KVO 动态创建的子类中,使用 method_setImplementation 方法来重写属性的 setter 方法。

void setAge(id self, SEL _cmd, int newAge) {[self willChangeValueForKey:@"age"];struct objc_super superStruct = {.receiver = self,.super_class = class_getSuperclass(object_getClass(self))};((void (*)(struct objc_super *, SEL, int))objc_msgSendSuper)(&superStruct, _cmd, newAge);[self didChangeValueForKey:@"age"];
}

KVO 的实现细节

以下是一个简单的示例,展示了 KVO 的一些底层实现细节:

@interface Person : NSObject
@property (nonatomic, assign) int age;
@end@implementation Person
@endPerson *person = [[Person alloc] init];
NSLog(@"Original class: %@", object_getClass(person)); // 输出原始类[person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
NSLog(@"Class after adding observer: %@", object_getClass(person)); // 输出动态子类[person setAge:30];
[person removeObserver:self forKeyPath:@"age"];

KVO 的工作流程

  1. 添加观察者

    • 调用 addObserver:forKeyPath:options:context: 方法时,KVO 会动态创建子类并重写 setter 方法。
    • 原始对象的类指针(isa 指针)被修改为新创建的子类。
  2. 触发观察

    • 当属性值发生变化时,调用重写后的 setter 方法。
    • 先触发 willChangeValueForKey:,然后调用原始 setter 方法更新属性值,最后触发 didChangeValueForKey:
    • 触发 didChangeValueForKey: 时,会通知所有观察者属性值已经改变。
  3. 移除观察者

    • 调用 removeObserver:forKeyPath: 方法时,KVO 会将类指针恢复为原始类,并移除重写的 setter 方法。

注意事项

  • 自动 KVO:KVO 默认仅支持通过 setter 方法修改属性值的情况。直接修改实例变量不会触发 KVO。
  • 手动触发 KVO:如果需要手动触发 KVO,可以调用 willChangeValue(forKey:)didChangeValue(forKey:) 方法。
[self willChangeValueForKey:@"age"];
_age = newValue;
[self didChangeValueForKey:@"age"];

总结

KVO 是 iOS 中基于动态特性实现的观察机制,通过动态子类化和方法重写实现。当属性值变化时,KVO 会通知所有注册的观察者。这一机制使得对象间的通信更加灵活和高效,但也需要注意在使用过程中正确添加和移除观察者,以避免内存泄漏或崩溃。

相关文章:

深入理解 KVO

在 iOS 中,KVO(Key-Value Observing)是一个强大的观察机制,它的底层实现相对复杂。KVO 利用 Objective-C 的动态特性,为对象的属性提供观察能力。 KVO 的底层实现 1. 动态子类化 当一个对象的属性被添加观察者时&am…...

当需要对大量数据进行排序操作时,怎样优化内存使用和性能?

文章目录 一、选择合适的排序算法1. 快速排序2. 归并排序3. 堆排序 二、数据结构优化1. 使用索引2. 压缩数据3. 分块排序 三、外部排序1. 多路归并排序 四、利用多核和并行计算1. 多线程排序2. 使用并行流 五、性能调优技巧1. 避免不必要的内存复制2. 缓存友好性3. 基准测试和性…...

kubernetes集群部署:node节点部署和cri-docker运行时安装(四)

安装前准备 同《kubernetes集群部署:环境准备及master节点部署(二)》 安装cri-docker 在 Kubernetes 1.20 版本之前,Docker 是 Kubernetes 默认的容器运行时。然而,Kubernetes 社区决定在 Kubernetes 1.20 及以后的…...

第五十章 Web Service URL 汇总

文章目录 第五十章 Web Service URL 汇总Web 服务 URLWeb 服务的端点WSDL 使用受密码保护的 WSDL URL 第五十章 Web Service URL 汇总 本主题总结了与 IRIS 数据平台 Web 服务相关的 URL。 Web 服务 URL 与 IRIS Web 服务相关的 URL 如下: Web 服务的端点 http…...

动态白色小幽灵404网站源码

动态白色小幽灵404网站源码&#xff0c;页面时单页HTML源码&#xff0c;将代码放到空白的html里面&#xff0c;鼠标双击html即可查看效果&#xff0c;或者上传到服务器&#xff0c;错误页重定向这个界面即可&#xff0c;喜欢的朋友可以拿去使用 <!DOCTYPE html> <ht…...

axios的使用,处理请求和响应,axios拦截器

1、axios官网 https://www.axios-http.cn/docs/interceptors 2、安装 npm install axios 3、在onMouunted钩子函数中使用axios来发送请求&#xff0c;接受响应 4.出现的问题&#xff1a; &#xff08;1&#xff09; 但是如果发送请求请求时间过长&#xff0c;回出现请求待处…...

visual studio 2017增加.cu文件

右击项目名称&#xff0c;选择生成依赖项>生成自定义把CUDA11.3target勾选上&#xff1b; 把带有cuda代码的.cpp文件和.cu文件右击属性>项类型>选择CUDA C/C 右击项目名称&#xff0c;C/C>命令行添加/D _CRT_SECURE_NO_WARNINGS&#xff1b; 选择CUDA C/C>命…...

linux 管道符 |

在Linux中&#xff0c;管道符&#xff08;|&#xff09;是一个非常重要的概念&#xff0c;它允许你将一个命令的输出作为另一个命令的输入。这种机制使得Linux命令可以非常灵活地进行组合&#xff0c;从而执行复杂的任务。 管道符的基本用法 假设你有两个命令&#xff1a;com…...

Android - SIP 协议

SIP 代表(会话发起协议)。 它是一种协议&#xff0c;可让应用程序轻松设置呼出和呼入语音呼叫&#xff0c;而无需直接管理会话、传输级通信或音频记录或回放。 SIP 应用程序 SIP 的一些常见应用是。 视频会议即时消息 开发要求 以下是开发 SIP 应用程序的要求 − Android 操作系…...

Python结合MobileNetV2:图像识别分类系统实战

一、目录 算法模型介绍模型使用训练模型评估项目扩展 二、算法模型介绍 图像识别是计算机视觉领域的重要研究方向&#xff0c;它在人脸识别、物体检测、图像分类等领域有着广泛的应用。随着移动设备的普及和计算资源的限制&#xff0c;设计高效的图像识别算法变得尤为重要。…...

【】AI八股-神经网络相关

Deep-Learning-Interview-Book/docs/深度学习.md at master amusi/Deep-Learning-Interview-Book GitHub 网上相关总结&#xff1a; 小菜鸡写一写基础深度学习的问题&#xff08;复制大佬的&#xff0c;自己复习用&#xff09; - 知乎 (zhihu.com) CV面试问题准备持续更新贴 …...

NodeJs的安装与环境变量配置

Node.js的环境变量配置主要涉及设置Node.js的安装路径、npm&#xff08;Node Package Manager&#xff09;的全局模块安装路径和缓存路径&#xff0c;以及可能需要的国内镜像源配置。以下是详细的配置步骤&#xff1a; 一、安装Node.js 下载Node.js安装包&#xff1a; 访问Nod…...

进程输入输出及终端属性学习

进程的标准输入输出 当主进程fork或exec子进程&#xff0c;文件描述符被继承&#xff0c;因此0,1,2句柄也被继承&#xff0c;从而使得telnet等服务&#xff0c;可以做到间接调用别的shell或程序。比如如果是远程登录使用的zsh&#xff0c;那么其会重定向到相应的pts $ ps|gre…...

关于redis集群和事务

最近为了核算项目的两个架构指标&#xff08;可用性和伸缩性&#xff09;&#xff0c;需要对项目中使用的Redis数据库的集群部署进行一定程度的了解&#xff0c;当然顺便再学习一遍它的事务细节。 既然我在上面把Redis称之为数据库&#xff0c;那么在我们目前的项目里&#xf…...

ctfshow-web入门-文件包含(web88、web116、web117)

目录 1、web88 2、web116 3、web117 1、web88 没有过滤冒号 : &#xff0c;可以使用 data 协议&#xff0c;但是过滤了括号和等号&#xff0c;因此需要编码绕过一下。 这里有点问题&#xff0c;我 (ls) 后加上分号发现不行&#xff0c;可能是编码结果有加号&#xff0c;题目…...

My sql 安装,环境搭建

以下以MySQL 8.0.36为例。 一、下载软件 1.下载地址官网&#xff1a;https://www.mysql.com 2. 打开官网&#xff0c;点击DOWNLOADS 然后&#xff0c;点击 MySQL Community(GPL) Downloads 3. 点击 MySQL Installer for Windows 4.点击Archives选择合适版本 5.选择后下载…...

JVM原理(二十):JVM虚拟机内存的三特性详解

1. 原子性、可进行、有序性 1.1. 原子性 Java内存模型围绕着在并发过程中如何处理原子性、可见性和有序性这三个特征来建立的。 Java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store和write这六个。我们大致可以认为&#xff0c;基本数据类型的访问、…...

Flink 窗口触发器(Trigger)(二)

Flink 窗口触发器(Trigger)(一) Flink 窗口触发器(Trigger)(二) Apache Flink 是一个开源流处理框架&#xff0c;用于处理无界和有界数据流。在 Flink 的时间窗口操作中&#xff0c;触发器&#xff08;Trigger&#xff09;是一个非常重要的概念&#xff0c;它决定了窗口何时应…...

CH12_函数和事件

第12章&#xff1a;Javascript的函数和事件 本章目标 函数的概念掌握常用的系统函数掌握类型转换掌握Javascript的常用事件 课程回顾 Javascript中的循环有那些&#xff1f;Javascript中的各个循环特点是什么&#xff1f;Javascript中的各个循环语法分别是什么&#xff1f;…...

Android- Framework 非Root权限实现修改hosts

一、背景 修改system/etc/hosts&#xff0c;需要具备root权限&#xff0c;而且remount后&#xff0c;才能修改&#xff0c;本文介绍非root状态下修改system/etc/hosts方案。 环境&#xff1a;高通 Android 13 二、方案 非root&#xff0c;system/etc/hosts只有只读权限&…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

go 里面的指针

指针 在 Go 中&#xff0c;指针&#xff08;pointer&#xff09;是一个变量的内存地址&#xff0c;就像 C 语言那样&#xff1a; a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10&#xff0c;通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...

TCP/IP 网络编程 | 服务端 客户端的封装

设计模式 文章目录 设计模式一、socket.h 接口&#xff08;interface&#xff09;二、socket.cpp 实现&#xff08;implementation&#xff09;三、server.cpp 使用封装&#xff08;main 函数&#xff09;四、client.cpp 使用封装&#xff08;main 函数&#xff09;五、退出方法…...