博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
轻量级KVO[译]
阅读量:5885 次
发布时间:2019-06-19

本文共 2477 字,大约阅读时间需要 8 分钟。

 
 
在这篇文章中,我会实现一个自己用的简单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.   if (self) { 
  3.     self.target = target; 
  4.     self.selector = selector; 
  5.     self.observedObject = object; 
  6.     self.keyPath = keyPath; 
  7.     [object addObserver:self forKeyPath:keyPath options:0 context:self]; 
  8.   } 
  9.   return self; 
 
一旦被观察者发生变化,我们就通知观察者(target),如果它还存在的话:
  1. - (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context 
  2. if (context == self) { 
  3.   id strongTarget = self.target; 
  4.   if ([strongTarget respondsToSelector:self.selector]) { 
  5. #pragma clang diagnostic push 
  6. #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 
  7.     [strongTarget performSelector:self.selector]; 
  8. #pragma clang diagnostic pop 
  9.   } 
 
最后在dealloc方法中移除观察者对象:
  1. - (void)dealloc 
  2.     id strongObservedObject = self.observedObject; 
  3.     if (strongObservedObject) { 
  4.         [strongObservedObject removeObserver:self forKeyPath:self.keyPath]; 
  5.     } 
这就是全部内容了。还有很多可以扩展的地方,比如增加block的支持,或者我比较喜欢的trick:再增加爱一个方便的构造方法用来第一次直接调用action。然而,我想的是展现出这个技术的核心部分,你可以根据自己的需求来调整它。
 
这个技术的优点是在使用KVO的时候不需要记住太多东西,仅仅retain住Observer对象,然后在完成的试试置为nil即可,剩下的会自动完成。
 
原文作者是Chris Eidhof, 的创办者
原文地址:
 
来源:
 
http://www.cocoachina.com/industry/20131106/7303.html

转载于:https://www.cnblogs.com/geek6/p/4187467.html

你可能感兴趣的文章
加快ALTER TABLE 操作速度
查看>>
学习笔记之软考数据库系统工程师教程(第一版)
查看>>
PHP 程序员的技术成长规划
查看>>
memcached 分布式聚类算法
查看>>
jquery css3问卷答题卡翻页动画效果
查看>>
$digest already in progress 解决办法——续
查看>>
mysql 数据类型
查看>>
Ubuntu 设置当前用户sudo免密码
查看>>
ionic 调用手机的打电话功能
查看>>
怎么使用阿里云直播服务应用到现在主流直播平台中
查看>>
判断点是否在三角形内
查看>>
知行合一
查看>>
jmeter插件之jsonpath提取响应结果和做断言
查看>>
推荐系统那点事 —— 基于Spark MLlib的特征选择
查看>>
linux 下RTL8723/RTL8188调试记录(命令行)【转】
查看>>
[Contiki系列论文之1]Contiki——为微传感器网络而生的轻量级的、灵活的操作系统...
查看>>
Android 网络编程 记录
查看>>
微软同步发行Windows 10和Windows 10 Mobile系统更新
查看>>
Zeppelin的入门使用系列之使用Zeppelin运行shell命令(二)
查看>>
form表单下的button按钮会自动提交表单的问题
查看>>