关于kvo,kvo能做什么?

kvo作为cocoa框架的重要特性之一,在底层框架中被大量使用。在特定的场合使用该特性往往能够带来难以想象的好处,让整个方案变得相当简洁和优雅。比如大名鼎鼎的下拉刷新的svpulltorefresh框架,其实现采用了category动态添加属性和kvo结合的方案,在egoRefresh框架的基础上获得了极大的改善,使调用者所要书写的代码量直接下降了一个量级。其中的奥秘在于通过kvo很好的处理了frame变化的问题,调用者不用再处理frame相关的代码,仅需要聚焦下拉刷新带来的业务逻辑事件本身。此后所有流行的下拉刷新框架无一例外的都采用了此方案。仅仅想象一下kvo本身的灵活性、广泛的适用性而言,其强大毋庸置疑;但是如何把它用好,则是一个很值得研究的课题。

直接使用kvo的麻烦?

麻烦1:

对于kvo来说,我认为他最大的坑在于生命周期的管理。举个例子一个对象A一旦发起了对别的对象属性的观察以后,在A对象释放之前,必须要手动调用解除监听的代码;否则在该对象属性变化时,则会引起crash。其实delegate以前也有类似的问题,但在iOS的演进过程中这个问题被解决了。解决方案是这样:在ARC以后delegate应该被设置成weak属性,这样一来当代理者被释放时,雇主的delegate属性是weak的情形中,这个delegate属性会被自动置为空,向一个空对象发消息,不会有任何问题。但是kvo的特性比较古老,苹果也未对其实现做任何改进,因此生命周期的管理对于合理的使用kvo非常重要。

麻烦2:

在另外一种场景下的使用也会crash:当一个对象A在没有发起观察之前就调用解除监听的代码时。所以很多人在调用解除监听的代码时都会引入try-catch来捕获这个错误,从而增加程序的健壮性。这也是一个不得已而为之的无奈之举。

麻烦3:

其他: kvo的调用代码本身略显繁琐,所有的kvo处理代码都被指定在一个方法内部,这样在监听多个对象时会导致该方法内部相当混乱,且该处理方法和调用方法一样,拥有4个参数,其中2个参数几乎可以说是没有作用(一般会被固定填写相同的值); 其中对于属性字段传递的参数是通过字符串来表示的,如果拼写错误也容易带来问题且难以检查(编译器不会告警)。这也是经常为人吐槽或者诟病的地方;人们总希望api清晰简洁,如果能够支持像block这样的现代语法则更棒。

kvo的封装思路

如上,我们认为kvo对于我们的技术链来说是一个不可或缺的环节;但是直接使用它的话,又有一些麻烦需要解决。所以,我们需要对它进行封装,封装的目的就是为了解决上面所列举的麻烦。

解决麻烦1:封装一个对象(我们将它看作是一个专门处理kvo的代理),专门用来管理属性的监听事件;此对象和一次监听动作唯一绑定;在该代理的dealloc里面我们会自动的调用解注册的方法。

解决麻烦2:在此前封装的代理对象中,我们会记录在此对象中的监听事件,如此一来我们自动调用的解注册方法和对外提供的解注册方法都能够保证安全(监听和解监听是一一对应的关系,且在时序上是监听在前,解监听在后)。

解决麻烦3: 封装api方法,支持block或target action的操作,并去除冗余参数。实际需要监听kvo的对象持有上面封装的代理对象,并从代理对象转发回调block或sel方法到实际需要监听kvo的对象。

这样一来我们就完成了一个简单的封装。我们还可以通过category和一些runtime技术的结合,来使得我们的api更简洁,使用更方便;这里就不再展开了。

More:封装示例+Demo

https://github.com/X-Team-X/SimpleKVO

上面的库是笔者从NSObject+YYAddForKVO简单修改而来,感谢ibireme对开源所作的贡献!

YYKit 原地址(author ibireme): https://github.com/ibireme/YYKit

参考和致谢

http://www.cocoachina.com/industry/20131106/7303.html

http://nshipster.com/key-value-observing/

https://github.com/th-in-gs/THObserversAndBinders

https://github.com/ibireme/YYKit/blob/master/YYKit/Base/Foundation/NSObject%2BYYAddForKVO.h

本文的写作参考了上述的文章和开源代码,也在此对其作者们表达感谢。

老调重弹:对kvo的封装思路的更多相关文章

  1. C#利用Emit反射实现AOP,以及平台化框架封装思路

    C#利用Emit反射实现AOP,以及平台化框架封装思路 这是前两天扒的一段动态代理AOP代码,用的Emit反射生成子类来实现代理模式,在这里做个小笔记,然后讨论一下AOP框架的实现思路. 首先是主函数 ...

  2. AFNetworking封装思路简析

    http://blog.csdn.net/qq_34101611/article/details/51698473 一.AFNetworking的发展 1. AFN 1.0版本 AFN 的基础部分是 ...

  3. 【SSM 7】Mybatis底层封装思路

    一.基本概述 在前面的博客中介绍到Mybatis的逆向生成工具,为我们生成了每个实体的基本增删改查的代码,那么每个实体都是那么多的代码,我们很容易的发现,有很大的相似性.对于这部分代码,应该予以抽象封 ...

  4. jquery插件封装思路整理

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. python+unittest框架整理(一点点学习前辈们的封装思路,一点点成长。。。)

    预期框架整理目标: 1.单个用例维护在单个.py文件中可单个执行,也可批量生成组件批量执行 2.对定位参数,定位方法,业务功能脚本,用例脚本,用例批量执行脚本,常用常量进行分层独立,各自维护在单独的. ...

  6. appium 元素文件 -查找元素 封装思路和方法

    方法1. try: target="//android.widget.TextView[@text='立即體驗']" element = WebDriverWait(dr,5,0. ...

  7. iOS的KVO使用和轻量级封装

    KVO的使用方法 注冊 [object addObserver:observer forKeyPath:@"text" options:NSKeyValueObservingOpt ...

  8. Vue + Element-ui实现后台管理系统(4)---封装一个ECharts组件的一点思路

    封装一个ECharts组件的一点思路 有关后台管理系统之前写过三遍博客,看这篇之前最好先看下这三篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-system ...

  9. 封装的ajax请求

    在做登录注册这类提交表单数据时,我们经常需要局部刷新网页来验证用户输入的信息,这就需要用到ajax请求,我们通常需要获取表单中的数据,发起ajax请求,通过服务程序,与数据库的数据进行比对,判断信息的 ...

随机推荐

  1. jquery概要--基础01

    jquery对象,DOM对象 var $cr = $('#cr');          var cr = $cr[0]; /var cr = $cr.get(0); var cr = document ...

  2. HDU 5212 Code

    筛法. 统计所有 [数] 的所有 [倍数] 的 [数] 的个数,即 i 的所有倍数 i, 2i, 3i, 4i...个数为 dp[i], 则所有 倍数两两结合共有 dp[i] * dp[i] 个. 此 ...

  3. wp 处理方法

    -DeepZoom:源于遥感影像的金字塔显示方式,提供了与高分辨率图像进行交互的能力,可以快速缩放图像而不影响应用的性能,加载或平移图像时可以光滑过度 -应用:高分辨率.极大图像的浏览,3D合成图像, ...

  4. TYVJ P1004 滑雪 Label:记忆化搜索

    背景 成成第一次模拟赛 第三道 描述     trs喜欢滑雪.他来到了一个滑雪场,这个滑雪场是一个矩形,为了简便,我们用r行c列的矩阵来表示每块地形.为了得到更快的速度,滑行的路线必须向下倾斜.    ...

  5. 达成成就:排名和AC数相同

    233333 纪念一下.(268会不会是幸运数字呢0.0

  6. TV测试中的按键长按操作模拟

    从UiAutomator在TV测试中的局限性说起: 智能TV的操作和手机的操作有很大不同,一般智能TV的操作为遥控器按键操作,来向TV OS发送  KeyCode,以完成指定操作. UiAutomat ...

  7. POST模拟百度登录和自动发帖

    这里用HttpClient发包模拟百度登录和发帖,验证码部分采用机器下载人工识别. 登陆百度的原理:1. 访问https://passport.baidu.com/v2/api/?getapi& ...

  8. CSS3选择器(一)之基本选择器

    CSS的选择器,我想大家并不会陌生吧,因为天天在使用,但对于CSS3的选择器,要运用的灵活到位,我想对很多朋友还是一定的难度,特别是CSS3中的:nth选择器.那么从现在开始我们先丢开他们版本的区别, ...

  9. iOS开发中代理使用出现的问题解决

    在给自定义的LHQTabBar设置代理的时候,定义的代理的属性的时候此时会报一个警告 我们需要遵守UITabBarDelegate的协议才行, 不过此时还有警告,警告已经变成了 此时我们需要在.m文件 ...

  10. php phpeclipse + xampp 配置安装过程

    就想test是否能配置成功,下载apache,php5.3,安装开始 apache的安装,一路next,遇到Server Information,随便填写即可,安装路径自己可选 php的安装,将下载的 ...