KVO底层探索和遇到的常见错误(一)

本文深入探讨了KVO(Key-Value Observing)的工作原理,包括动态子类创建、属性观察机制及常见错误分析,并提供了详细的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

序言

前几天公交车上看了一篇百度大神的关于 KVO 探索的博客。我实地验证了一下子,也遇到了好多问题,一番各种查阅资料之后,决定总结分享一下,供各位看官指点哈~

KVO的原理

下面的原理仔细品尝喔~多读几遍就可以理解了,当然理解不了就按我说的来点 KVO 的代码,最后肿能理解

1.当一个 object(对象) 有观察者时候,动态创建这个 object(对象) 的类的子类

2.对于每个被观察的 property(属性),重写其 setter 方法

3.在重写的 setter 方法中调用 -willChangeValueForKey: 和 -didChangeValueForKey: 通知观察者

4.当一个 property(属性) 没有观察者时,删除重写的方法

5.当没有 observer(观察者) 观察任何一个 property(属性) 时,删除动态创建的子类

Demo 验证

Demo简单到要死,觉着扔一张图就看的明白,比废话一大堆简单多了,有时候看文字是件晦涩的事情,还得一个字一个字的理解,所以此处扔图,有想看Demo的点我穿越

1291197-9c33b5d854af3671.jpg

接下来看看 KVO 是怎么动态创建子类的:

  • 断点1—>代码和 Log 日志

1291197-b9d0b92be40ff49e.jpg

断点1-代码

1291197-74280677b1964a18.jpg

断点1-Log

对比上述2张图,我们在断点1处,在控制台分别使用- class 和 object_getClass() 打印person对象的类和真实的类,下面的断点2和断点3都按此方法打印 Log日志。

  • 断点2—>代码和 Log 日志

1291197-c83709540d7e839a.jpg

断点2-代码

1291197-623c99fa548eacc4.jpg

断点2-Log

  • 断点3—>代码和 Log 日志

1291197-5120c041769b1c7e.jpg

断点3-代码

1291197-d6e3e2a9eb0fb1ef.jpg

断点3-Log

瞧~,断点2的 Log 日志信息突然冒出了一个

NSKVONotifying_HQMPerson,这是什么鬼。。。

我们知道为一个对象addObsever时候,也就是被观察时,

framework使用runtime动态创建了一个HQMPerson类的子类NSKVONotifying_HQMPerson,而为了不让外部知道这一行为,

NSKVONotifying_HQMPerson重写了-class方法返回之前的类,所以通过-class方法查看的类没有变化,但是通过object_getClass()方式就会暴露出来发生了何种变化,因为这个object_getClass()返回的是这个对象的isa指针,isa指针指向的一定是这个对象所属的类。如下图:

1291197-0b8469b33a3d83ed.jpg

isa 指向 xx

常见错误

1.错误1-remove观察者

1467705629131135.jpg

造成该崩溃信息的代码片段如下:

1467705649445679.jpg

崩溃信息的代码片段

上述代码是对 person 这个对象添加了监听,而removeObserver方法却是移除的self,显然这是一个很低级的错误。

解决方法: 观察谁,谁就应该移除也就是偷窥谁,谁就发毛,所以就该跑

2.错误2-属性的值修改了的信息收到了,但是并没有处理

1291197-5ee624cd0a543427.jpg

其实这个很简单就是你addObserver了,但是方法-observeValueForKeyPath:ofObject:change:context:却没有实现,这个算是最低级的了。。。

解决方法:

PS:只要你注册了 KVO,这个方法就必须实现

3.错误3-添加和移除时候,context上下文不一致

1467705733213504.jpg

代码片段如下:

1467705751946600.jpg

context上下文不一致

解决方法:

一般来说context都传nil

4.错误4-致命性

1291197-dbf5b4a9eeb0f4c1.jpg

说实话遇到这个错误,我还是真不知道从何入手(皆因对 KVO 的理解不够深),先看出现这种崩溃的原始代码:

1467705803538283.jpg

原始代码片段

只要运行,程序就会爽快的崩溃。。。看下我的注释,然后在对比一下崩溃日志信息(HQMPerson 类的实例被释放了,但是 KVO 中还有关于他的注册信息)。

实际上,只要你明白 KVO 的知识:在添加观察者的时候,观察者对象与被观察的属性所属的对象都不会被retain,然而在这些对象被释放后,相关的监听信息却还存在,(ARC环境下)KVO做的处理是直接让程序崩溃。

解决方法:

既然明白了这一点,我们就知道如何修改了(ARC 环境下),如下修改:

1291197-3667e0c0e0d1dac9.jpg

修改后代码片段

关于 KVO 的触发方式-自动和手动,以及更深的底层探索待续喔。。。会出 xxx(二)呢(这部分得参考Apple的官方文档,英文有压力)

内容概要:本文介绍了多种开发者工具及其对开发效率的提升作用。首先,介绍了两款集成开发环境(IDE):IntelliJ IDEA 以其智能代码补全、强大的调试工具项目管理功能适用于Java开发者;VS Code 则凭借轻量级多种编程语言的插件支持成为前端开发者的常用工具。其次,提到了基于 GPT-4 的智能代码生成工具 Cursor,它通过对话式编程显著提高了开发效率。接着,阐述了版本控制系统 Git 的重要性,包括记录代码修改、分支管理协作功能。然后,介绍了 Postman 作为 API 全生命周期管理工具,可创建、测试文档化 API,缩短前后端联调时间。再者,提到 SonarQube 这款代码质量管理工具,能自动扫描代码并检测潜在的质量问题。还介绍了 Docker 容器化工具,通过定义应用的运行环境依赖,确保环境致性。最后,提及了线上诊断工具 Arthas 性能调优工具 JProfiler,分别用于生产环境排障性能优化。 适合人群:所有希望提高开发效率的程序员,尤其是有定开发经验的软件工程师技术团队。 使用场景及目标:①选择合适的 IDE 提升编码速度代码质量;②利用 AI 编程助手加快开发进程;③通过 Git 实现高效的版本控制团队协作;④使用 Postman 管理 API 的全生命周期;⑤借助 SonarQube 提高代码质量;⑥采用 Docker 实现环境致性;⑦运用 Arthas JProfiler 进行线上诊断性能调优。 阅读建议:根据个人或团队的需求选择适合的工具,深入理解每种工具的功能特点,并在实际开发中不断实践优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值