KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的实时变化情况并作出响应。网上广为流传普及的一个例子是利用KVO检测股票价格的变动,例如这里。这个例子作为扫盲入门还是可以的,但是当应用场景比较复杂时,里面的一些细节还是需要改进的,里面有多个地方存在crash的危险。本文旨在逐步递进深入地探讨出一种目前比较健壮稳定的KVO实现方案,弥补网上大部分教程的不足!

首先,假设我们的目标是在一个UITableViewController内对tableview的contentOffset进行实时监测,很容易地使用KVO来实现为。

在初始化方法中加入:

1
[_tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];

在dealloc中移除KVO监听:

1
[_tableView removeObserver:self forKeyPath:@"contentOffset" context:nil];

添加默认的响应回调方法:

1
2
3
4
5
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                        change:(NSDictionary *)change context:(void *)context
{
       [self doSomethingWhenContentOffsetChanges];
}

好了,KVO实现就到此完美结束了,拜拜。。。开个玩笑,肯定没这么简单的,这样的代码太粗糙了,当你在controller中添加多个KVO时,所有的回调都是走同上述函数,那就必须对触发回调函数的来源进行判断。判断如下:

1
2
3
4
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                        change:(NSDictionary *)change context:(void *)context
{
    if (object == _tableView && [keyPath isEqualToString:@"contentOffset"]) {

1
[self doSomethingWhenContentOffsetChanges];
1
} }

你以为这样就结束了吗?答案是否定的!我们假设当前类(在例子中为UITableViewController)还有父类,并且父类也有自己绑定了一些其他KVO呢?我们看到,上述回调函数体中只有一个判断,如果这个if不成立,这次KVO事件的触发就会到此中断了。但事实上,若当前类无法捕捉到这个KVO,那很有可能是在他的superClass,或者super-superClass...中,上述处理砍断了这个链。合理的处理方式应该是这样的:

1
2
3
4
5
6
7
8
9
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                        change:(NSDictionary *)change context:(void *)context
{
    if (object == _tableView && [keyPath isEqualToString:@"contentOffset"]) {
        [self doSomethingWhenContentOffsetChanges];
else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

这样就结束了吗?答案仍旧是否定的。潜在的问题有可能出现在dealloc中对KVO的注销上。KVO的一种缺陷(其实不能称为缺陷,应该称为特性)是,当对同一个keypath进行两次removeObserver时会导致程序crash,这种情况常常出现在父类有一个kvo,父类在dealloc中remove了一次,子类又remove了一次的情况下。不要以为这种情况很少出现!当你封装framework开源给别人用或者多人协作开发时是有可能出现的,而且这种crash很难发现。不知道你发现没,目前的代码中context字段都是nil,那能否利用该字段来标识出到底kvo是superClass注册的,还是self注册的?

回答是可以的。我们可以分别在父类以及本类中定义各自的context字符串,比如在本类中定义context为@"ThisIsMyKVOContextNotSuper";然后在dealloc中remove observer时指定移除的自身添加的observer。这样iOS就能知道移除的是自己的kvo,而不是父类中的kvo,避免二次remove造成crash。

=======================================================

by 编程小翁@博客园

from: http://www.cnblogs.com/wengzilin/p/4346775.html

iOS下KVO使用过程中的陷阱相关推荐

  1. oracle中job的retry次数,有大佬帮忙看下我安装过程中到底出啥问题了么..

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 有大佬帮忙看下我安装过程中到底出啥问题了么.. 之前说我监听不对,我调了下.监听米问题了, 但是现在还是提示我"插件执行方法失败.." ...

  2. oracle impdp无法打开日志文件,Solaris 下 Oracle impdp 过程中出现的问题

    ORA-39002: invalid operation ORA-39070: Unable to open the log file. ORA-29283: invalid file operati ...

  3. Solaris 下 Oracle impdp 过程中出现的问题

    ORA-39002: invalid operation ORA-39070: Unable to open the log file. ORA-29283: invalid file operati ...

  4. iOS APP 上架审核过程中常见问题整理

    一 .iOS APP 上架流程简介 1. 申请开发者账号 苹果的开发者账号主要分为个人(Individual).公司(Company).企业(Enterprise).高校(University)四种类 ...

  5. Windows10下BurpSuite安装过程中存在的一些问题以及解决办法(图文解析)

    安装问题 一.JAVAC测试失败 二.双击burp-loader-keygen.jar没用 三.run点击无效 本人初次安装burpsuite过程中出现了许多问题,找了许多许多的教程,这几天全部忙在这 ...

  6. win10下mediasoup搭建过程中的一些坑记录

    我们原来基于Janus的webrtc系统基本上可用了,系统目前最高到5万人同时在线,不过确实发现Janus的一些不足,对于我这种喜欢c++的人来说,看Janus的代码实在是比较痛苦,于是处于研究目的, ...

  7. phpmyadmin/scripts/setup.php,Linux下phpMyAdmin安装过程中的问题解决

    1.下载phpMyAdmin,自己想办法拷到/var/www/html下,并解压,开始使用. http://IP/phpMyAdmin测试 cp config.sample.inc.php confi ...

  8. win10系统下Eplan使用过程中卡死现象

    尝试过的解决方法: (1)复制Version.dll文件:关闭Eplan软件,复制Version.dll文件,右键已经安装好的Eplan软件图标,点击"属性",点击"打开 ...

  9. win10下安装ensp过程中,安装winpcap出现报错

    注:因安装ensp有依赖包,所以在安装ensp前需要下载virtualbox.winpcap和wireshark. 这里我安装的是以下版本 安装包:链接:https://pan.xunlei.com/ ...

最新文章

  1. iOS Winding Rules 缠绕规则
  2. 5c用计算机怎么打,再一次谈谈%5c暴库的利用 -电脑资料
  3. java数字不等于_java – 仅使用set中的数字查找等于或大于给定目标的总和
  4. android pdfjet_GitHub - lnj721/PdfBuilder: Android端使用图片生成PDF文件
  5. 风控模型面试问题汇总
  6. bom 根据一阶 BOM 表整理多阶层 BOM 表
  7. win11中利用IIS10搭建asp网站
  8. matlab资产组合最优配置,[转载]资产组合有效前沿的解和最优解(MATLAB语言)
  9. 网页制作html怎么居中,网页制作中的水平居中和垂直居中解决方法集合
  10. html如何制作水滴效果图,html+css实现充电水滴融合特效代码
  11. 如何在AD软件中创建自定义区域铺铜
  12. 【操作系统】成组链接法详解
  13. 修复 Windows 映像
  14. 六、品达通用权限系统__pd-tools-log
  15. 课设-药店的药品销售统计系统(排序应用)
  16. 大话卷积神经网络CNN(干货满满)
  17. 解决数字和英文字母结合检索出现高亮重复问题
  18. PLY文档翻译——利用Python进行词法和语法分析
  19. shell脚本之n之内的质数
  20. 2020-08-25

热门文章

  1. 【风控体系】互联网反欺诈体系漫谈
  2. JS中map()与forEach()的用法
  3. 从重采样到数据合成:如何处理机器学习中的不平衡分类问题?
  4. 2017西南计算机数学基础,[0838]《计算机数学基础》西南大学 2017 秋学期 计算机专业 作业题目及参考答案资料讲解.docx...
  5. 并发编程-14线程安全策略之并发容器(J.U.C)中的集合类
  6. Spring-引用Bean的属性值
  7. Android Application 之 allowBackup 属性浅析
  8. Java学习笔记(八)--字符串生成器
  9. linux printf 刷新,linux下printf中\n刷新缓冲区的疑问(已解决)
  10. 学习笔记Hadoop(一)—— Hadoop介绍(1)——认识大数据