在这篇文章中,我会实现一个自己用的简单KVO类,我认为KVO非常棒,然而对于我大部分的使用场景来说,有这两个问题:
1. 我不喜欢在observeValueForKeyPath:ofObject:change:context:方法里通过keyPath值来做调度,当Observe比较多的对象时,会使得代码变得杂乱和迷惑。 
2. 必须手动的来注册和删除一个观察者,如果能自动做就好了。
 
So,我们开始这个实现。这个技巧我第一次是在THObserversAndBinders项目中见到,本篇内容也仅仅描述了一下里面的做法,同时做了简化。
 
首先,我们定义一下我们的这个类,我们这个帮助类的类名是Observer:
  1. @interface Observer : NSObject
  2. + (instancetype)observerWithObject:(id)object
  3. keyPath:(NSString*)keyPath
  4. target:(id)target
  5. selector:(SEL)selector;
  6. @end
 Observer类的这个类方法有四个参数,每个参数都是自解释的,我选择使用target/action模式,当然也可以使用block,但是那样的话需要做weakSelf/strongSelf的转换,你懂的,通常来说分来来做比较好。
 
我们做的是在初始化方法中设置KVO,并在dealloc方法中移除。这意味着一旦Observer对象被retain,我们就有了一个观察者,下面这段代码是从我的一个ViewCOntroller中拿来的:
  1. self.usernameObserver = [Observer observerWithObject:self.user
  2. keyPath:@"name"
  3. target:self
  4. selector:@selector(usernameChanged)];
把这个Observer对象作为一个属性放在ViewController中来保证被retain,一旦我们的Viewcontroller被释放,就会设置它为nil,observer就停止观察了。
 
在这个实现中,使用一个weak引用指向被观察对象和观察者(target)是很重要的,如果两个中的其中一个是nil,我们就停止向观察者发送消息。
  1. @interface Observer ()
  2. @property (nonatomic, weak) id target;
  3. @property (nonatomic) SEL selector;
  4. @property (nonatomic, weak) id observedObject;
  5. @property (nonatomic, copy) NSString* keyPath;
  6. @end
 
初始化器里设置KVO通知,使用self作为context,如果我们会有一个子类也添加类似的观察者时就很有必要了。
  1. - (id)initWithObject:(id)object keyPath:(NSString*)keyPath target:(id)target selector:(SEL)selector
  2. {
  3. if (self) {
  4. self.target = target;
  5. self.selector = selector;
  6. self.observedObject = object;
  7. self.keyPath = keyPath;
  8. [object addObserver:self forKeyPath:keyPath options:0 context:self];
  9. }
  10. return self;
  11. }
 
一旦被观察者发生变化,我们就通知观察者(target),如果它还存在的话:
  1. - (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
  2. {
  3. if (context == self) {
  4. id strongTarget = self.target;
  5. if ([strongTarget respondsToSelector:self.selector]) {
  6. #pragma clang diagnostic push
  7. #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
  8. [strongTarget performSelector:self.selector];
  9. #pragma clang diagnostic pop
  10. }
  11. }
  12. }
 
最后在dealloc方法中移除观察者对象:
  1. - (void)dealloc
  2. {
  3. id strongObservedObject = self.observedObject;
  4. if (strongObservedObject) {
  5. [strongObservedObject removeObserver:self forKeyPath:self.keyPath];
  6. }
  7. }
这就是全部内容了。还有很多可以扩展的地方,比如增加block的支持,或者我比较喜欢的trick:再增加爱一个方便的构造方法用来第一次直接调用action。然而,我想的是展现出这个技术的核心部分,你可以根据自己的需求来调整它。
 
这个技术的优点是在使用KVO的时候不需要记住太多东西,仅仅retain住Observer对象,然后在完成的试试置为nil即可,剩下的会自动完成。
 
原文作者是Chris Eidhof,objc.io的创办者
 
 
http://www.cocoachina.com/industry/20131106/7303.html

轻量级KVO[译]的更多相关文章

  1. LevelDB:一个快速轻量级的key-value存储库(译)

    作者:Jeff Dean, Sanjay Ghemawat 原文:http://leveldb.googlecode.com/svn/trunk/doc/index.html 译者:phylips@b ...

  2. (译)KVO的内部实现

    09年的一篇文章,比较深入地阐述了KVO的内部实现.   KVO是实现Cocoa Bindings的基础,它提供了一种方法,当某个属性改变时,相应的objects会被通知到.在其他语言中,这种观察者模 ...

  3. [转](译)KVO的内部实现

    转载自:http://www.cocoachina.com/applenews/devnews/2014/0107/7667.html   09年的一篇文章,比较深入地阐述了KVO的内部实现.   K ...

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

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

  5. 轻量级表达式树解析框架Faller

    有话说 之前我写了3篇关于表达式树解析的文章 干货!表达式树解析"框架"(1) 干货!表达式树解析"框架"(2) 干货!表达式树解析"框架" ...

  6. Model-View-ViewModel for iOS [译]

    如果你已经开发一段时间的iOS应用,你一定听说过Model-View-Controller, 即MVC.MVC是构建iOS app的标准模式.然而,最近我已经越来越厌倦MVC的一些缺点.在本文,我将重 ...

  7. 轻量级富文本编辑器wangEditor源码结构介绍

    1. 引言 wangEditor——一款轻量级html富文本编辑器(开源软件) 网站:http://www.wangeditor.com/ demo演示:http://www.wangeditor.c ...

  8. 【原】IOS中KVO模式的解析与应用

    最近老翁在项目中多处用到了KVO,深感这种模式的好处.现总结如下: 一.概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知.简单 ...

  9. [译] Swift 的响应式编程

    原文  https://github.com/bboyfeiyu/iOS-tech-frontier/blob/master/issue-3/Swift的响应式编程.md 原文链接 : Reactiv ...

随机推荐

  1. wamp升级php7

    原文:http://blog.csdn.net/cheng6251/article/details/50730441 1.下载php7   http://windows.PHP.net/downloa ...

  2. 【三小时学会Kubernetes!(二) 】Kubernetes 简介及Pod实践

    Kubernetes 简介 我向你保证我没有夸大其词,读完本文你会问“为什么我们不称它为 Supernetes?” Kubernetes 是什么? 从容器启动微服务后,我们有一个问题,让我们通过如下问 ...

  3. ACM ICPC 2010–2011, Northeastern European Regional Contest St Petersburg – Barnaul – Tashkent – Tbilisi, November 24, 2010

    ACM ICPC 2010–2011, Northeastern European Regional Contest St Petersburg – Barnaul – Tashkent – Tbil ...

  4. 在线前端开发平台 Plunker

    Plunker 网站 : http://plnkr.co/ Plunker 是一个用来创建.协作和分享 Web 开发思路的在线社区.编辑界面如下图所示: 特点: 基于 Node.js 环境运行 实时的 ...

  5. [Vue]组件——组件的data 必须是一个函数

    普通的Vue实例data是一个对象: data: { count: 0 } 组件的data是一个方法: data: function () { return { count: 0 } } 详情见官网: ...

  6. spring mvc:练习:表单验证(javaConfig配置和注解)

    使用Spring表单标签, 表单验证使用 JSR303 的验证注解,hibernate-validators,提供了使用MessageSource和访问静态资源(如CSS,JavaScript,图片) ...

  7. flask学习(十二):for循环遍历

    一. 字典的遍历 语法和python一样,可以使用items().keys().values().iteritems().iterkeys().itervalues() {% for k, v in ...

  8. docker 快速搭建 WordPress

    安装Docker 环境:阿里云服务器 镜像:CentOs 7.4 64 https://docs.docker.com/install/linux/docker-ce/centos/ 安装WordPr ...

  9. TI IPNC Web网页之进阶修改

    GoDB内嵌HTML 原始的页面里面已经有一个内嵌HTML的例子了,那就是维护支持页面.下图是稍微修改后的页面...请自行脑补. 这里使用的是上一节所说的gdo containter的方法. 打开ma ...

  10. 逐步实现hash算法(基于BKDRhash函数)

    哈希(Hash)算法,即散列函数.它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程.同时,哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出.hash算法 ...