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([keyPath isEqualToString:@"text"])
    {
        NSLog(@"text:@%@", change[NSKeyValueChangeNewKey]);
    }
}
  • 释放的时候取消注册
[object removeObserver:self forKeyPath:@"text"];

这里有几个问题

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

KVO的封装

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

  • 定义一个观察者类
@interface XYObserver : NSObject
@end

@interface XYObserver ()

@property (nonatomic, assign) XYObserverType type;      // 观察者的类型

@property (nonatomic, weak) id target;                  // 被观察的对象的值改变时后的响应方法所在的对象
@property (nonatomic, assign) SEL selector;             // 被观察的对象的值改变时后的响应方法
@property (nonatomic, copy) XYObserver_block_sourceObject_new_old block;        // 值改变时执行的block

@property (nonatomic, assign) id  sourceObject;         // 被观察的对象
@property (nonatomic, strong) NSString *keyPath;        // 被观察的对象的keyPath

-(instancetype) initWithSourceObject:(id)sourceObject keyPath:(NSString*)keyPath target:(id)target selector:(SEL)selector type:(XYObserverType)type;

-(instancetype) initWithSourceObject:(id)sourceObject keyPath:(NSString*)keyPath block:(XYObserver_block_sourceObject_new_old)block;

@end
  • 添加NSObject关于观察者的类别
@interface NSObject (XYObserver)

@property (nonatomic, readonly, strong) NSMutableDictionary *observers;

/**
 * api parameters 说明
 *
 * sourceObject 被观察的对象

 * keyPath 被观察的属性keypath

 * target 默认是self

 * selector @selector(propertyNew:)
            @selector(propertyNew:old:)
            @selector(propertyIn:new:)
            @selector(propertyIn:new:old:)

 * type 根据selector自动赋值

 * block selector, block二选一
 */
-(void) observeWithObject:(id)sourceObject property:(NSString*)property;
-(void) observeWithObject:(id)sourceObject property:(NSString*)property block:(XYObserver_block_sourceObject_new_old)block;

-(void) removeObserverWithObject:(id)sourceObject property:(NSString *)property;
-(void) removeObserverWithObject:(id)sourceObject;
-(void) removeAllObserver;

@end
  • 在这里我们查询的实现的方法
-(void) observeWithObject:(id)object property:(NSString*)property{
 SEL aSel = NSSelectorFromString([NSString stringWithFormat:@"%@New:", property]);
    if ([self respondsToSelector:aSel]) {
        [self observeWithObject:object
                        keyPath:property
                         target:self
                       selector:aSel
                        type:XYObserverType_new];
        return;
    }
    .
    .
    .
}
  • 用block的话就直接保存
-(void) observeWithObject:(id)object property:(NSString*)property block:(XYObserver_block_sourceObject_new_old)block{
    [self observeWithObject:object keyPath:property block:block];
}
  • 处理实现方法
-(void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
    __weak __typeof(self) weakSelf = self;
    if (_block) {
        _block(weakSelf, change[NSKeyValueChangeNewKey], change[NSKeyValueChangeOldKey]);
        return;
    }

    if (_type == XYObserverType_new) {
        action(_target, _selector, change[NSKeyValueChangeNewKey]);
    }else if (_type == XYObserverType_new_old) {
        action(_target, _selector, change[NSKeyValueChangeNewKey], change[NSKeyValueChangeOldKey]);
    }else if (_type == XYObserverType_self_new) {
        action(_target, _selector, self, change[NSKeyValueChangeNewKey]);
    }else if (_type == XYObserverType_self_new_old) {
        action(_target, _selector, self, change[NSKeyValueChangeNewKey], change[NSKeyValueChangeOldKey]);
    }
}
  • 把所有的观察者添加到一个字典里
-(void) observeWithObject:(id)object keyPath:(NSString*)keyPath target:(id)target selector:(SEL)selector type:(XYObserverType)type{
    XYObserver *ob = [[XYObserver alloc] initWithSourceObject:object keyPath:keyPath target:target selector:selector type:type];

    NSString *key = [NSString stringWithFormat:@"%@_%@", object, keyPath];
    [self.observers setObject:ob forKey:key];
}

-(void) observeWithObject:(id)object property:(NSString*)property block:(XYObserver_block_sourceObject_new_old)block{
    [self observeWithObject:object keyPath:property block:block];
}

-(id) observers{
    id object = objc_getAssociatedObject(self, NSObject_observers);

    if (nil == object) {
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:8];
        objc_setAssociatedObject(self, NSObject_observers, dic, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        return dic;
    }

    return object;
}
  • 当对象释放的时候会清空字典里的观察者对象,在观察者对象的dealloc方法里面取消注册观察者
-(void) dealloc
{
    if (_sourceObject) { [_sourceObject removeObserver:self forKeyPath:_keyPath]; }
}

使用的demo

[self observeWithObject:self property:@"testKVO"];
[self observeWithObject:self property:@"testKVO2" block:^(id sourceObject, id newValue, id oldValue) {
        NSLogD(@"obj:%@ new:%@ old:%@", sourceObject, newValue, oldValue);
    }];

-(void) testKVOIn:(id)sourceObject new:(id)newValue old:(id)oldValue{
    NSLogD(@"obj:%@ new:%@ old:%@", sourceObject, newValue, oldValue);
}

这个封装的优点是在使用KVO的时候不需要记住太多东西.

代码可以在https://github.com/uxyheaven/XYQuickDevelop下载到

iOS的KVO使用和轻量级封装,布布扣,bubuko.com

时间: 2024-10-13 09:00:48

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

iOS开发-KVO的奥秘

iOS开发-KVO的奥秘 字数2933 阅读3842 评论28 喜欢57 序言 在iOS开发中,苹果提供了许多机制给我们进行回调.KVO(key-value-observing)是一种十分有趣的回调机制,在某个对象注册监听者后,在被监听的对象发生改变时,对象会发送一个通知给监听者,以便监听者执行回调操作.最常见的KVO运用是监听scrollView的contentOffset属性,来完成用户滚动时动态改变某些控件的属性实现效果,包括渐变导航栏.下拉刷新控件等效果. 渐变导航栏 使用 KVO的使用

Android6.0M权限管理实战,完美轻量级封装

转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53189359 本文出自[DylanAndroid的博客] Android6.0M权限管理实战,完美轻量级封装 随着Android版本的不断更新,Android再权限管理方面的诟病越来越明显.Google的Android开发人员也意识到了Android应用在权限管理方面的各种问题,让好多用户摸不着头脑就使用了用户的隐私数据. 为了在权限这方面加强管理,给用户一个比较好的体验.A

iOS KVC/KVO总结

http://www.cnblogs.com/QM80/p/3647819.html 如果要修改对象的属性值 1.一般情况下是直接利用对象属性的set方法来修改: Student *stu = [[Student alloc] init]; // set方法的两种书写格式 [stu setAge:10]; stu.age = 10; 2.但是如果不知道对象类型呢?那么就可以运用KVC键值编码(Key Value Coding) 间接的修改对象属性 KVC实现方式是:使用字符串来描述对象需要修改的

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

======================================================= 原创文章,转载请注明 编程小翁@博客园,邮件[email protected],欢迎各位与我在C/C++/Objective-C/机器视觉等领域展开交流! ======================================================= KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的实时变化情况并作

ios 之kvo&kvc的使用

转载:http://www.cnblogs.com/kenshincui/p/3871178.html 概述 由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于Ruby.Python的动态特性,例如动态类型.动态加载.动态绑定等.今天我们着重介绍ObjC中的键值编码(KVC).键值监听(KVO)特性: 键值编码KVC 键值监听KVO 键值编码KVC 我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象.其实由于Obj

iOS 8:【转】封装iOS静态库注意事项

源地址:http://fann.im/blog/2014/01/12/ios-static-library/ 做一个 iOS 静态库需要注意的东西: namespace 冲突.静态库用了某第三方库,项目也用了同样的第三方库,在编译的时候就会有 duplicate symbol 错误,因为有两份同样的第三方库.解决办法就是把用到的第三方库加上自定义前缀,包括类名.delegate 协议.常量名,尤其需要注意 Category 的方法名要修改. 封装静态库的时候应尽量避免引入重量级第三方库,多自己进

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

IOS中有许多网络请求的函数,同步的,异步的,通过delegate异步回调的. 在做一个项目的时候,上网看了很多别人的例子,发现都没有一个简单的,方便的异步请求的封装例子.我这里要给出的封装代码,是异步的,post的请求方式.通过ios的原生函数简单封装.通过这个封装可以方便的访问http服务器,获取数据,也可以容易的异步加载网络图片. 首先新建一个httpHelper类,在这个类里进行封装,封装的函数名称就叫做post,参数有请求的地址url,请求的参数params,返回数据后回调的函数blo

IOS中KVO模式的解析与应用

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

iOS开发——KVO/KVC&OC与Swift篇详解

Swift中使用KVC和KVO的类都必须必须继承自NSObject KVC key-value coding 是1种间接访问对象的机制 key的值就是属性名称的字符串,返回的value是任意类型,需要自己转化为需要的类型 KVC主要就是两个方法 (1)通过key设置对应的属性 (2)通过key获得对应的属性 举例 class TestForKVC:NSObject{ var hwcCSDN = "hello world" } var instance = TestForKVC() va