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"];
这里有几个问题
- 注冊的时候參数过多
- 释放的时候必须取消注冊
- 仅仅有一个回调,当注冊的观察者过多的时候,会使得代码变得杂乱
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]; }
}
- 为了方便书写,定义几个宏
#define ON_KVO_1_( __property ) -(void) __property##New:(id)newValue
#define ON_KVO_2_( __property ) -(void) __property##New:(id)newValue old:(id)oldValue
#define ON_KVO_3_( __property ) -(void) __property##In:(id)sourceObject new:(id)newValue
#define ON_KVO_4_( __property ) -(void) __property##In:(id)sourceObject new:(id)newValue old:(id)oldValue
使用的demo
[self observeWithObject:self property:@"testKVO"];
ON_KVO_4_(testKVO){
NSLogD(@"obj:%@ new:%@ old:%@", sourceObject, newValue, oldValue);
}
[self observeWithObject:self property:@"testKVO2" block:^(id sourceObject, id newValue, id oldValue) {
NSLogD(@"obj:%@ new:%@ old:%@", sourceObject, newValue, oldValue);
}];
这个封装的长处是在使用KVO的时候不须要记住太多东西..
iOS的KVO使用和轻量级封装的更多相关文章
- IOS中KVO模式的解析与应用
IOS中KVO模式的解析与应用 最近老翁在项目中多处用到了KVO,深感这种模式的好处.现总结如下: 一.概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修 ...
- iOS下KVO使用过程中的陷阱 (转发)
iOS下KVO使用过程中的陷阱 KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的实时变化情况并作出响应.网上广为流传普及的一个例子是利用KV ...
- 轻量级封装DbUtils&Mybatis之三MyBatis分页
MyBatis假分页 参考DefaultResultSetHandler的skipRows方法. 温馨提示:部分代码请参考轻量级封装DbUtils&Mybatis之一概要 解决方案 1)之前公 ...
- 【原】iOS下KVO使用过程中的陷阱
KVO,全称为Key-Value Observing,是iOS中的一种设计模式,用于检测对象的某些属性的实时变化情况并作出响应.网上广为流传普及的一个例子是利用KVO检测股票价格的变动,例如这里.这个 ...
- iOS开发——post异步网络请求封装
IOS中有许多网络请求的函数,同步的,异步的,通过delegate异步回调的. 在做一个项目的时候,上网看了很多别人的例子,发现都没有一个简单的,方便的异步请求的封装例子.我这里要给出的封装代码,是异 ...
- 【原】IOS中KVO模式的解析与应用
最近老翁在项目中多处用到了KVO,深感这种模式的好处.现总结如下: 一.概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知.简单 ...
- iOS之KVO和KVC
概述 由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于Ruby.Python的动态特性,例如动态类型.动态加载.动态绑定等.今天我们着重介绍ObjC中的键值编码(KVC).键值监听( ...
- 轻量级封装DbUtils&Mybatis之二Dbutils
DbUtils入门 Apache出品的极为轻量级的Jdbc访问框架,核心类只有两个:QueryRunner和ResultSetHandler. 各类ResultSetHandler: ArrayHan ...
- 轻量级封装DbUtils&Mybatis之一概要
Why 一时兴起,自以为是的对Jdbc访问框架做了一个简单的摸底,近期主要采用Mybatis,之前也有不少采用Dbutils,因此希望能让这两个框架折腾的更好用. DbUtils:非常简单的Jdbc访 ...
随机推荐
- 栈C++实现
栈的核心是LIFO(Last In First Out),即后进先出 出栈和入栈只会对栈顶进行操作,栈底永远为0.如果是入栈,要将入栈元素赋值给栈数组,再将栈顶上移一位:出栈时要先将栈顶下移一位,再将 ...
- FZU 2138——久违的月赛之一——————【贪心】
久违的月赛之一 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Stat ...
- mongodb配置文件与启动
数据库配置文件 mongo.cnf #日志文件位置 logpath=/data/db/journal/mongodb.log (这些都是可以自定义修改的) # 以追加方式写入日志 logappend= ...
- VirtualBox-4.3.0启动报错及解决办法
今天装了VirtualBox-4.3.0-89960-Win.exe,安装过程后启动时报错: 虚拟电脑控制台-严重错误(标题) 创建 COM 对象失败. 应用程序将被中断. 被召者 RC: E_NOI ...
- YII2应用结构
应用中最重要的目录和文件(假设应用根目录是 basic): 一般来说,应用中的文件可被分为两类:在 basic/web 下的和在其它目录下的.前者可以直接通过 HTTP 访问(例如浏览器),后者不能也 ...
- [转]微信小程序开发踩坑记录
本文转自:http://www.cnblogs.com/NKnife/p/6283605.html 1.由于小程序wx.request()方法是异步的,在app.js执行ajax后,各分页加载app. ...
- MYSQL连接字符串参数解析(解释)
被迫转到MySQL数据库,发现读取数据库时,tinyint类型的值都被转化为boolean了,这样大于1的值都丢失,变成true了.查阅资料MySQL中无Boolean类型,都是存储为tinyint了 ...
- golang学习之go简单博客应用
先说说golang的语法吧,个人觉得有以下特点: 简洁,不管是变量.方法声明,还是代码编写,均十分简洁,效率也比较高 非纯粹面向对象,但是go的struct类似c的struct,go的结构体还可以进行 ...
- Rabbit的直连交换机direct
直连交换机类型为:direct.加入了路由键routingKey的概念. 就是说 生产者投递消息给指定交换机的指定路由键. 只有绑定了此交换机指定路由键的消息队列才可以收到消息. 生产者: packa ...
- 解决maven项目中,缺少 maven dependencies
因为项目需要将普通项目转换为maven项目,在右键 ’项目‘configure 后,添加maven后,发现缺少 maven dependencies,于是从网上找了一些处理措施,大体上是在.class ...