KVO的使用方法

  • 注冊
  1. [object addObserver:observer forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:nil];
  • 实现回调方法
  1. -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
  2. {
  3. if([keyPath isEqualToString:@"text"])
  4. {
  5. NSLog(@"text:@%@", change[NSKeyValueChangeNewKey]);
  6. }
  7. }
  • 释放的时候取消注冊
  1. [object removeObserver:self forKeyPath:@"text"];

这里有几个问题

  1. 注冊的时候參数过多
  2. 释放的时候必须取消注冊
  3. 仅仅有一个回调,当注冊的观察者过多的时候,会使得代码变得杂乱

KVO的封装

以下我们将针对这几个问题进行封装

  • 定义一个观察者类
  1. @interface XYObserver : NSObject
  2. @end
  3.  
  4. @interface XYObserver ()
  5.  
  6. @property (nonatomic, assign) XYObserverType type; // 观察者的类型
  7.  
  8. @property (nonatomic, weak) id target; // 被观察的对象的值改变时后的响应方法所在的对象
  9. @property (nonatomic, assign) SEL selector; // 被观察的对象的值改变时后的响应方法
  10. @property (nonatomic, copy) XYObserver_block_sourceObject_new_old block; // 值改变时运行的block
  11.  
  12. @property (nonatomic, assign) id sourceObject; // 被观察的对象
  13. @property (nonatomic, strong) NSString *keyPath; // 被观察的对象的keyPath
  14.  
  15. -(instancetype) initWithSourceObject:(id)sourceObject keyPath:(NSString*)keyPath target:(id)target selector:(SEL)selector type:(XYObserverType)type;
  16.  
  17. -(instancetype) initWithSourceObject:(id)sourceObject keyPath:(NSString*)keyPath block:(XYObserver_block_sourceObject_new_old)block;
  18.  
  19. @end
  • 加入NSObject关于观察者的类别
  1. @interface NSObject (XYObserver)
  2.  
  3. @property (nonatomic, readonly, strong) NSMutableDictionary *observers;
  4.  
  5. /**
  6. * api parameters 说明
  7. *
  8. * sourceObject 被观察的对象
  9.  
  10. * keyPath 被观察的属性keypath
  11.  
  12. * target 默认是self
  13.  
  14. * selector @selector(propertyNew:)
  15. @selector(propertyNew:old:)
  16. @selector(propertyIn:new:)
  17. @selector(propertyIn:new:old:)
  18.  
  19. * type 依据selector自己主动赋值
  20.  
  21. * block selector, block二选一
  22. */
  23. -(void) observeWithObject:(id)sourceObject property:(NSString*)property;
  24. -(void) observeWithObject:(id)sourceObject property:(NSString*)property block:(XYObserver_block_sourceObject_new_old)block;
  25.  
  26. -(void) removeObserverWithObject:(id)sourceObject property:(NSString *)property;
  27. -(void) removeObserverWithObject:(id)sourceObject;
  28. -(void) removeAllObserver;
  29.  
  30. @end
  • 在这里我们查询的实现的方法
  1. -(void) observeWithObject:(id)object property:(NSString*)property{
  2. SEL aSel = NSSelectorFromString([NSString stringWithFormat:@"%@New:", property]);
  3. if ([self respondsToSelector:aSel]) {
  4. [self observeWithObject:object
  5. keyPath:property
  6. target:self
  7. selector:aSel
  8. type:XYObserverType_new];
  9. return;
  10. }
  11. .
  12. .
  13. .
  14. }
  • 用block的话就直接保存
  1. -(void) observeWithObject:(id)object property:(NSString*)property block:(XYObserver_block_sourceObject_new_old)block{
  2. [self observeWithObject:object keyPath:property block:block];
  3. }
  • 处理实现方法
  1. -(void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
  2. {
  3. __weak __typeof(self) weakSelf = self;
  4. if (_block) {
  5. _block(weakSelf, change[NSKeyValueChangeNewKey], change[NSKeyValueChangeOldKey]);
  6. return;
  7. }
  8.  
  9. if (_type == XYObserverType_new) {
  10. action(_target, _selector, change[NSKeyValueChangeNewKey]);
  11. }else if (_type == XYObserverType_new_old) {
  12. action(_target, _selector, change[NSKeyValueChangeNewKey], change[NSKeyValueChangeOldKey]);
  13. }else if (_type == XYObserverType_self_new) {
  14. action(_target, _selector, self, change[NSKeyValueChangeNewKey]);
  15. }else if (_type == XYObserverType_self_new_old) {
  16. action(_target, _selector, self, change[NSKeyValueChangeNewKey], change[NSKeyValueChangeOldKey]);
  17. }
  18. }
  • 把全部的观察者加入到一个字典里
  1. -(void) observeWithObject:(id)object keyPath:(NSString*)keyPath target:(id)target selector:(SEL)selector type:(XYObserverType)type{
  2. XYObserver *ob = [[XYObserver alloc] initWithSourceObject:object keyPath:keyPath target:target selector:selector type:type];
  3. NSString *key = [NSString stringWithFormat:@"%@_%@", object, keyPath];
  4. [self.observers setObject:ob forKey:key];
  5. }
  6. -(void) observeWithObject:(id)object property:(NSString*)property block:(XYObserver_block_sourceObject_new_old)block{
  7. [self observeWithObject:object keyPath:property block:block];
  8. }
  9. -(id) observers{
  10. id object = objc_getAssociatedObject(self, NSObject_observers);
  11. if (nil == object) {
  12. NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:8];
  13. objc_setAssociatedObject(self, NSObject_observers, dic, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  14. return dic;
  15. }
  16. return object;
  17. }
  • 当对象释放的时候会清空字典里的观察者对象,在观察者对象的dealloc方法里面取消注冊观察者
  1. -(void) dealloc
  2. {
  3. if (_sourceObject) { [_sourceObject removeObserver:self forKeyPath:_keyPath]; }
  4. }
  • 为了方便书写,定义几个宏
  1. #define ON_KVO_1_( __property ) -(void) __property##New:(id)newValue
  2. #define ON_KVO_2_( __property ) -(void) __property##New:(id)newValue old:(id)oldValue
  3. #define ON_KVO_3_( __property ) -(void) __property##In:(id)sourceObject new:(id)newValue
  4. #define ON_KVO_4_( __property ) -(void) __property##In:(id)sourceObject new:(id)newValue old:(id)oldValue

使用的demo

  1. [self observeWithObject:self property:@"testKVO"];
  2.  
  3. ON_KVO_4_(testKVO){
  4. NSLogD(@"obj:%@ new:%@ old:%@", sourceObject, newValue, oldValue);
  5. }
  6.  
  7. [self observeWithObject:self property:@"testKVO2" block:^(id sourceObject, id newValue, id oldValue) {
  8. NSLogD(@"obj:%@ new:%@ old:%@", sourceObject, newValue, oldValue);
  9. }];

这个封装的长处是在使用KVO的时候不须要记住太多东西..

代码能够在https://github.com/uxyheaven/XYQuickDevelop下载到

iOS的KVO使用和轻量级封装的更多相关文章

  1. IOS中KVO模式的解析与应用

    IOS中KVO模式的解析与应用 最近老翁在项目中多处用到了KVO,深感这种模式的好处.现总结如下: 一.概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修 ...

  2. iOS下KVO使用过程中的陷阱 (转发)

    iOS下KVO使用过程中的陷阱   KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的实时变化情况并作出响应.网上广为流传普及的一个例子是利用KV ...

  3. 轻量级封装DbUtils&Mybatis之三MyBatis分页

    MyBatis假分页 参考DefaultResultSetHandler的skipRows方法. 温馨提示:部分代码请参考轻量级封装DbUtils&Mybatis之一概要 解决方案 1)之前公 ...

  4. 【原】iOS下KVO使用过程中的陷阱

    KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的实时变化情况并作出响应.网上广为流传普及的一个例子是利用KVO检测股票价格的变动,例如这里.这个 ...

  5. iOS开发——post异步网络请求封装

    IOS中有许多网络请求的函数,同步的,异步的,通过delegate异步回调的. 在做一个项目的时候,上网看了很多别人的例子,发现都没有一个简单的,方便的异步请求的封装例子.我这里要给出的封装代码,是异 ...

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

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

  7. iOS之KVO和KVC

    概述 由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于Ruby.Python的动态特性,例如动态类型.动态加载.动态绑定等.今天我们着重介绍ObjC中的键值编码(KVC).键值监听( ...

  8. 轻量级封装DbUtils&Mybatis之二Dbutils

    DbUtils入门 Apache出品的极为轻量级的Jdbc访问框架,核心类只有两个:QueryRunner和ResultSetHandler. 各类ResultSetHandler: ArrayHan ...

  9. 轻量级封装DbUtils&Mybatis之一概要

    Why 一时兴起,自以为是的对Jdbc访问框架做了一个简单的摸底,近期主要采用Mybatis,之前也有不少采用Dbutils,因此希望能让这两个框架折腾的更好用. DbUtils:非常简单的Jdbc访 ...

随机推荐

  1. step4: Xpath的使用

    XPath 是一门在 XML 文档中查找信息的语言.XPath 可用来在 XML 文档中对元素和属性进行遍历. XPath 包含一个标准函数库. XPath 是一个 W3C 标准. 语法简介: htt ...

  2. 常用工具说明--搭建基于rietveld的CodeReview平台(未测试)

    为什么要codereview . 整个团队的编码风格是统一的. . 有高手能对自己的代码指点一二,从而提高编码水平. . 减少低级错误的出现 . 约束自己写高质量的代码,因为是要给人看的. 我们对co ...

  3. JavaScript中Undefined 和 Null的区别

    Undefined 这个值表示变量不含有值. 可以通过将变量的值设置为 null 来清空变量. 例如: <script> var person; var car="Volvo&q ...

  4. 提交代码至coding.net

    1.首先在本地任意目录下创建项目 2.cmd切换至该目录下,然后依次输入: git init git add . git commit -m "version 3.9" git r ...

  5. Asp.NET MVC4 + Ajax 实现多文件上传

    本文转自http://www.cnblogs.com/freeliver54/archive/2013/05/15/3079700.html JS部分测试可以,jQuery部分没有测试先留着 HTML ...

  6. explode 把字符串打散为数组

    // 显示的字段列表 $smarty->assign('field_show', explode(',',$list_name)); explode(separator,string,limit ...

  7. Oracle查询表名超过长度限制的表

    SELECT T.table_name, LENGTH(TRIM(T.table_name)) FROM user_tables t ORDER BY LENGTH(TRIM(t.table_name ...

  8. Struts2 学习(二)

    一.Struts2 配置文件 1.配置多个配置文件 在大部分应用里,随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿. 为了避免struts.xm ...

  9. OkHttp完全解析之整体调用流程

    前言:阅读好的代码如同观赏美景一样的美妙 OkHttp是一个Square公司在github开源的Java网络请求框架,非常流行.OkHttp 的代码并不是特别庞大,代码很多巧妙的实现,非常值得学习. ...

  10. flex固定底部栏

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...