在这篇文章中,我会实现一个自己用的简单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. Android -- 文件上传到服务器

    1. 文件上传的两种方式 (1) HttpClient (2)AsyncHttpClient (开源框架: https://github.com/loopj/android-async-http) 示 ...

  2. tp5.1升级

    # php think version v5.1.23 # composer update Loading composer repositories with package information ...

  3. JS的scrollIntoView

    scrollIntoView(alignWithTop)  滚动浏览器窗口或容器元素,以便在当前视窗的可见范围看见当前元素.如果alignWithTop为true,或者省略它,窗口会尽可能滚动到自身顶 ...

  4. Microsoft's OWIN implementation, the Katana project

    参考: https://github.com/aspnet/AspNetKatana/ https://github.com/aspnet/AspNetKatana/wiki/Roadmap

  5. 15个Android通用流行框架大全

    1. 缓存 DiskLruCache  Java实现基于LRU的磁盘缓存 2.图片加载 Android Universal Image Loader  一个强大的加载,缓存,展示图片的库 Picass ...

  6. Python之如何删除pandas DataFrame的某一/几列

    删除pandas DataFrame的某一/几列: 方法一:直接del DF['column-name']   方法二:采用drop方法,有下面三种等价的表达式: 1. DF= DF.drop('co ...

  7. react 子组件改变父组件状态

    class Father extends Component {     construtor(props){         super(props);         this.state={   ...

  8. nyoj299——如何优雅的写矩阵快速幂

    Matrix Power Series 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 Given a n × n matrix A and a positive i ...

  9. Python之路day12 web 前端(HTML+ css)

    HTML文档 文档树: Doctype Doctype告诉浏览器使用什么样的html或xhtml规范来解析html文档 有和无的区别 BackCompat:标准兼容模式未开启(或叫怪异模式[Quirk ...

  10. Ubuntu 安装GNU Scientific library(GSL)

    注: 此系列为自己之前所搭建网站内容. 由于论文数据处理的需要,需要使用libeemd这个包,需要安装gsl科学库,windows下没有办法,只能转战ubuntu进行科学计算. GSL(GNU Sci ...