轻量级KVO[译]

在这篇文章中,我会实现一个自己用的简单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的创办者

原文地址:Lightweight Key-Value Observing

来源:代码手工艺人

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

时间: 2024-10-19 15:52:27

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

iOS的KVO使用和轻量级封装

KVO的用法 注册 [object addObserver:observer forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:nil]; 实现回调方法 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if(

(译)KVO的内部实现

09年的一篇文章,比较深入地阐述了KVO的内部实现. KVO是实现Cocoa Bindings的基础,它提供了一种方法,当某个属性改变时,相应的objects会被通知到.在其他语言中,这种观察者模式通常需要单独实现,而在Objective-C中,通常无须增加额外代码即可使用. 概览 这是怎么实现的呢?其实这都是通过Objective-C强大的运行时(runtime)实现的.当你第一次观察某个object时,runtime会创建一个新的继承原先class的subclass.在这个新的class中,

iOS中消息的传递机制(KVO、Notification、delegation、block以及target-action)---转载

注1:本文由破船[博客]译自Communication Patterns. 本文目录如下所示: 可用的机制 做出正确的选择 Framework示例 小结 每个应用程序或多或少,都由一些松耦合的对象构成,这些对象彼此之间要想很好的完成任务,就需要进行消息传递.本文将介绍所有可用的消息传递机制,并通过示例来介绍这些机制在苹果的Framework中如何使用,同时,还介绍了一些最佳实践建议,告诉你什么时机该选择使用什么机制. 虽然这一期的主题是关于Foundation Framework的,不过本文中还

[译] Swift 的响应式编程

原文  https://github.com/bboyfeiyu/iOS-tech-frontier/blob/master/issue-3/Swift的响应式编程.md 原文链接 : Reactive Swift 原文作者 : Agnes Vasarhelyi 译文出自 : 开发技术前线 www.devtf.cn 译者 :Mr.Simple 校对者:Lollypo 状态 : 完成 让我们首先回到Apple刚推出Objective-C的继任者-Swift的时候,那真是一个非比寻常的时刻. Sir

【JavaScript】【译】编写高性能JavaScript

英文链接:Writing Fast, Memory-Efficient JavaScript 很多JavaScript引擎,如Google的V8引擎(被Chrome和Node所用),是专门为需要快速执行的大型JavaScript应用所设计的.如果你是一个开发者,并且关心内存使用情况与页面性能,你应该了解用户浏览器中的JavaScript引擎是如何运作的.无论是V8,SpiderMonkey的(Firefox)的Carakan(Opera),Chakra(IE)或其他引擎,这样做可以帮助你更好地优

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

1. 引言 wangEditor——一款轻量级html富文本编辑器(开源软件) 网站:http://www.wangeditor.com/ demo演示:http://www.wangeditor.com/wangEditor/demo.html 下载(github):https://github.com/wangfupeng1988/wangEditor QQ群:164999061 从我发布wangEditor到现在,大概有七八个月了,随着近期增加的插入视频,表情,地图这三个功能,目前为止基本

IOS中KVO模式的解析与应用

最近老翁在项目中多处用到了KVO,深感这种模式的好处.现总结如下: 一.概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知.简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了. KVO其实也是“观察者”设计模式的一种应用.我的看法是,这种模式有利于两个类间的解耦合,尤其是对于 业务逻辑与视图控制 这两个功能的解耦合. 二.引子 先来看个引子: 有一个业务类:Walker,在这个类内部只负责关于

0521.如何拆分View Controller进而实现轻量级的View Controller[UIKit]

参考文章来自objcio网站 为什么要编写轻量级的View Controller?? 1.作为iOS项目中最大的文件,ViewControllers中的代码复用率几乎是最低的 2.重量级的View COntroller加大了测试的复杂度. 所以关注ViewController的瘦身,把业务逻辑.网络请求.Views的代码移到合适的地方,进而提高代码可读性.降低耦合.提高复用.降低测试难度极为重要 一.把DataSource和其他Protocols分离出来 比如uiTableView中的DataS

The Swift Programming Language-官方教程精译Swift(8)闭包 -- Closures

闭包是功能性自包含模块,可以在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其他一些编程语言中的 lambdas 比较相似. 闭包可以捕获和存储其所在上下文中任意常量和变量的引用. 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包.Swift会为您管理在捕获过程中涉及到的内存操作.  注意:如果您不熟悉 捕获 (capturing) 这个概念也不用担心,后面会详细对其进行介绍. 在 函数 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采