老调重弹:对kvo的封装思路-阿里云开发者社区

开发者社区> 管振纬> 正文

老调重弹:对kvo的封装思路

简介: 关于kvo,kvo能做什么? kvo作为cocoa框架的重要特性之一,在底层框架中被大量使用。在特定的场合使用该特性往往能够带来难以想象的好处,让整个方案变得相当简洁和优雅。
+关注继续查看

关于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
本文的写作参考了上述的文章和开源代码,也在此对其作者们表达感谢。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
7422 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
9713 0
使用SSH远程登录阿里云ECS服务器
远程连接服务器以及配置环境
2129 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
9136 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
11221 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
10735 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
4461 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
20984 0
+关注
管振纬
资深移动开发者
300
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《Nacos架构&原理》
立即下载
《看见新力量:二》电子书
立即下载
云上自动化运维(CloudOps)白皮书
立即下载