KVO底层探索和遇到的常见错误(一)
2016-07-07 08:38
239 查看
序言
前几天公交车上看了一篇百度大神的关于 KVO 探索的博客。我实地验证了一下子,也遇到了好多问题,一番各种查阅资料之后,决定总结分享一下,供各位看官指点哈~
KVO的原理
下面的原理仔细品尝喔~多读几遍就可以理解了,当然理解不了就按我说的来点 KVO 的代码,最后肿能理解
1.当一个 object(对象) 有观察者时候,动态创建这个 object(对象) 的类的子类
2.对于每个被观察的 property(属性),重写其 setter 方法
3.在重写的 setter 方法中调用 -willChangeValueForKey: 和 -didChangeValueForKey: 通知观察者
4.当一个 property(属性) 没有观察者时,删除重写的方法
5.当没有 observer(观察者) 观察任何一个 property(属性) 时,删除动态创建的子类
Demo 验证
Demo简单到要死,觉着扔一张图就看的明白,比废话一大堆简单多了,有时候看文字是件晦涩的事情,还得一个字一个字的理解,所以此处扔图,有想看Demo的点我穿越。
![](http://cc.cocimg.com/api/uploads/20160705/1467705356530617.jpg)
接下来看看 KVO 是怎么动态创建子类的:
断点1—>代码和 Log 日志
![](http://cc.cocimg.com/api/uploads/20160705/1467705412479025.jpg)
断点1-代码
![](http://cc.cocimg.com/api/uploads/20160705/1467705433217891.jpg)
断点1-Log
对比上述2张图,我们在断点1处,在控制台分别使用- class 和 object_getClass() 打印person对象的类和真实的类,下面的断点2和断点3都按此方法打印 Log日志。
断点2—>代码和 Log 日志
![](http://cc.cocimg.com/api/uploads/20160705/1467705496214257.jpg)
断点2-代码
![](http://cc.cocimg.com/api/uploads/20160705/1467705509466608.jpg)
断点2-Log
断点3—>代码和 Log 日志
![](http://cc.cocimg.com/api/uploads/20160705/1467705551550806.jpg)
断点3-代码
![](http://cc.cocimg.com/api/uploads/20160705/1467705559981392.jpg)
断点3-Log
瞧~,断点2的 Log 日志信息突然冒出了一个
NSKVONotifying_HQMPerson,这是什么鬼。。。
我们知道为一个对象addObsever时候,也就是被观察时,
framework使用runtime动态创建了一个HQMPerson类的子类NSKVONotifying_HQMPerson,而为了不让外部知道这一行为,
NSKVONotifying_HQMPerson重写了-class方法返回之前的类,所以通过-class方法查看的类没有变化,但是通过object_getClass()方式就会暴露出来发生了何种变化,因为这个object_getClass()返回的是这个对象的isa指针,isa指针指向的一定是这个对象所属的类。如下图:
![](http://cc.cocimg.com/api/uploads/20160705/1467705600350052.jpg)
isa 指向 xx
常见错误
1.错误1-remove观察者
![](http://cc.cocimg.com/api/uploads/20160705/1467705629131135.jpg)
造成该崩溃信息的代码片段如下:
![](http://cc.cocimg.com/api/uploads/20160705/1467705649445679.jpg)
崩溃信息的代码片段
上述代码是对 person 这个对象添加了监听,而removeObserver方法却是移除的self,显然这是一个很低级的错误。
解决方法: 观察谁,谁就应该移除也就是偷窥谁,谁就发毛,所以就该跑
2.错误2-属性的值修改了的信息收到了,但是并没有处理
![](http://cc.cocimg.com/api/uploads/20160705/1467705704788245.jpg)
其实这个很简单就是你addObserver了,但是方法-observeValueForKeyPath:ofObject:change:context:却没有实现,这个算是最低级的了。。。
解决方法:
PS:只要你注册了 KVO,这个方法就必须实现
3.错误3-添加和移除时候,context上下文不一致
![](http://cc.cocimg.com/api/uploads/20160705/1467705733213504.jpg)
代码片段如下:
![](http://cc.cocimg.com/api/uploads/20160705/1467705751946600.jpg)
context上下文不一致
解决方法:
一般来说context都传nil
4.错误4-致命性
![](http://cc.cocimg.com/api/uploads/20160705/1467705789981000.jpg)
说实话遇到这个错误,我还是真不知道从何入手(皆因对 KVO 的理解不够深),先看出现这种崩溃的原始代码:
![](http://cc.cocimg.com/api/uploads/20160705/1467705803538283.jpg)
原始代码片段
只要运行,程序就会爽快的崩溃。。。看下我的注释,然后在对比一下崩溃日志信息(HQMPerson 类的实例被释放了,但是 KVO 中还有关于他的注册信息)。
实际上,只要你明白 KVO 的知识:在添加观察者的时候,观察者对象与被观察的属性所属的对象都不会被retain,然而在这些对象被释放后,相关的监听信息却还存在,(ARC环境下)KVO做的处理是直接让程序崩溃。
解决方法:
既然明白了这一点,我们就知道如何修改了(ARC 环境下),如下修改:
![](http://cc.cocimg.com/api/uploads/20160705/1467705918314364.jpg)
修改后代码片段
尾
关于 KVO 的触发方式-自动和手动,以及更深的底层探索待续喔。。。会出 xxx(二)呢(这部分得参考Apple的官方文档,英文有压力)
前几天公交车上看了一篇百度大神的关于 KVO 探索的博客。我实地验证了一下子,也遇到了好多问题,一番各种查阅资料之后,决定总结分享一下,供各位看官指点哈~
KVO的原理
下面的原理仔细品尝喔~多读几遍就可以理解了,当然理解不了就按我说的来点 KVO 的代码,最后肿能理解
1.当一个 object(对象) 有观察者时候,动态创建这个 object(对象) 的类的子类
2.对于每个被观察的 property(属性),重写其 setter 方法
3.在重写的 setter 方法中调用 -willChangeValueForKey: 和 -didChangeValueForKey: 通知观察者
4.当一个 property(属性) 没有观察者时,删除重写的方法
5.当没有 observer(观察者) 观察任何一个 property(属性) 时,删除动态创建的子类
Demo 验证
Demo简单到要死,觉着扔一张图就看的明白,比废话一大堆简单多了,有时候看文字是件晦涩的事情,还得一个字一个字的理解,所以此处扔图,有想看Demo的点我穿越。
![](http://cc.cocimg.com/api/uploads/20160705/1467705356530617.jpg)
接下来看看 KVO 是怎么动态创建子类的:
断点1—>代码和 Log 日志
![](http://cc.cocimg.com/api/uploads/20160705/1467705412479025.jpg)
断点1-代码
![](http://cc.cocimg.com/api/uploads/20160705/1467705433217891.jpg)
断点1-Log
对比上述2张图,我们在断点1处,在控制台分别使用- class 和 object_getClass() 打印person对象的类和真实的类,下面的断点2和断点3都按此方法打印 Log日志。
断点2—>代码和 Log 日志
![](http://cc.cocimg.com/api/uploads/20160705/1467705496214257.jpg)
断点2-代码
![](http://cc.cocimg.com/api/uploads/20160705/1467705509466608.jpg)
断点2-Log
断点3—>代码和 Log 日志
![](http://cc.cocimg.com/api/uploads/20160705/1467705551550806.jpg)
断点3-代码
![](http://cc.cocimg.com/api/uploads/20160705/1467705559981392.jpg)
断点3-Log
瞧~,断点2的 Log 日志信息突然冒出了一个
NSKVONotifying_HQMPerson,这是什么鬼。。。
我们知道为一个对象addObsever时候,也就是被观察时,
framework使用runtime动态创建了一个HQMPerson类的子类NSKVONotifying_HQMPerson,而为了不让外部知道这一行为,
NSKVONotifying_HQMPerson重写了-class方法返回之前的类,所以通过-class方法查看的类没有变化,但是通过object_getClass()方式就会暴露出来发生了何种变化,因为这个object_getClass()返回的是这个对象的isa指针,isa指针指向的一定是这个对象所属的类。如下图:
![](http://cc.cocimg.com/api/uploads/20160705/1467705600350052.jpg)
isa 指向 xx
常见错误
1.错误1-remove观察者
![](http://cc.cocimg.com/api/uploads/20160705/1467705629131135.jpg)
造成该崩溃信息的代码片段如下:
![](http://cc.cocimg.com/api/uploads/20160705/1467705649445679.jpg)
崩溃信息的代码片段
上述代码是对 person 这个对象添加了监听,而removeObserver方法却是移除的self,显然这是一个很低级的错误。
解决方法: 观察谁,谁就应该移除也就是偷窥谁,谁就发毛,所以就该跑
2.错误2-属性的值修改了的信息收到了,但是并没有处理
![](http://cc.cocimg.com/api/uploads/20160705/1467705704788245.jpg)
其实这个很简单就是你addObserver了,但是方法-observeValueForKeyPath:ofObject:change:context:却没有实现,这个算是最低级的了。。。
解决方法:
PS:只要你注册了 KVO,这个方法就必须实现
3.错误3-添加和移除时候,context上下文不一致
![](http://cc.cocimg.com/api/uploads/20160705/1467705733213504.jpg)
代码片段如下:
![](http://cc.cocimg.com/api/uploads/20160705/1467705751946600.jpg)
context上下文不一致
解决方法:
一般来说context都传nil
4.错误4-致命性
![](http://cc.cocimg.com/api/uploads/20160705/1467705789981000.jpg)
说实话遇到这个错误,我还是真不知道从何入手(皆因对 KVO 的理解不够深),先看出现这种崩溃的原始代码:
![](http://cc.cocimg.com/api/uploads/20160705/1467705803538283.jpg)
原始代码片段
只要运行,程序就会爽快的崩溃。。。看下我的注释,然后在对比一下崩溃日志信息(HQMPerson 类的实例被释放了,但是 KVO 中还有关于他的注册信息)。
实际上,只要你明白 KVO 的知识:在添加观察者的时候,观察者对象与被观察的属性所属的对象都不会被retain,然而在这些对象被释放后,相关的监听信息却还存在,(ARC环境下)KVO做的处理是直接让程序崩溃。
解决方法:
既然明白了这一点,我们就知道如何修改了(ARC 环境下),如下修改:
![](http://cc.cocimg.com/api/uploads/20160705/1467705918314364.jpg)
修改后代码片段
尾
关于 KVO 的触发方式-自动和手动,以及更深的底层探索待续喔。。。会出 xxx(二)呢(这部分得参考Apple的官方文档,英文有压力)
相关文章推荐
- 100度小例子
- Entity Framework Tutorial Basics(2):What is Entity Framework?
- Entity Framework Tutorial Basics(1):Introduction
- Spring的applicationContext.xml--spring 配置文件详解
- 旅游小例子
- iOS中保证线程安全的几种方式与性能对比
- 07.07C
- 动画小例子
- 3728 联合权值
- border-radius画企鹅
- 背水一战 Windows 10 (21) - 绑定: x:Bind 绑定, x:Bind 绑定之 x:Phase, 使用绑定过程中的一些技巧
- 簡單SQLite 數據庫操作Demo
- Intent传递javabean
- spring面试大全
- 数字变换
- artDialog 配置参数
- 设计模式之代理模式
- 第七次作业(未完成)
- C#读写中文文件
- CRectTrack使用,设置外框样式