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访 ...
随机推荐
- Android OpenGL教程-第五课【转】
第五课 3D空间: 我们使用多边形和四边形创建3D物体,在这一课里,我们把三角形变为立体的金子塔形状,把四边形变为立方体. 先看看三角形的顶点变成啥了 private float[] mTriangl ...
- 从零实现一个简易的jQuery框架之二—核心思路详解
如何读源码 jQuery整体框架甚是复杂,也不易读懂.但是若想要在前端的路上走得更远.更好,研究分析前端的框架无疑是进阶路上必经之路.但是庞大的源码往往让我们不知道从何处开始下手.在很长的时间里我也被 ...
- python-入门教程(-)
# hello worldprint("hello world") # 变量msg = "使用变量"print(msg) # 字符串大小写变换(仅针对英文)na ...
- 从Word中拷贝字段用于MySQL建表
1.SQL 基础表 建立 USE [Test] GO /****** Object: Table [dbo].[CreateTable] Script Date: 10/17/2016 14:07:1 ...
- VS快捷键设置无效
使用Resharper 后发现有些快捷键冲突,但是在工具-选项-键盘 设置后不管用,后来发现有一个移除功能,即移走原来的快捷键; 先选择下拉框1中自己用不到的快捷键,然后移除掉; 备注: 注意观察 快 ...
- c# winfrom 页面的enter变为tab 功能使用 在特定的按钮里面如何继续当enter使用求大神帮忙解答一下 !!急
enter 当tab 键用 已经实现 :例如按回车的时候切换一直走 ,走到一个按钮如何让回车键在这个按钮的时候还是执行enter按钮的功能而不是tab 求大神解答一下, 目前页面tab功能改为 ...
- json数据发送时浏览器提示“保存”解决
数据以json形式发送的时候,部分浏览器不能直接解析,而是提示是否保存,nodejs的express应用中可以通过如下代码解决该问题: router.get('/', function (req, r ...
- [android] 网络链接类型和渠道
1.实现方式 1.1使用HttpUrlConnection 1.2使用HttpClient 1.3使用Socket,比如:豌豆荚,聊天工具 2.通讯渠道 2.1 WLAN(wi-fi),100米左右的 ...
- JAVA中LinkedLockingQueue的简单使用
1.相关知识的了解 阻塞队列:当队列为空时,去队列中取数据会被阻塞.当队列满时,往队列中放数据会被阻塞. 非阻塞队列:当队列为空时,去队列取数据会直接返回失败,队列满时,往队列中放数据会直接返回失 ...
- mybatis笔记<二> 整合spring
mybatis与spring整合需要添加几个jar包,mybatis-spring, spring-context, spring-jdbc 1. spring ioc只要一个jar包就ok 2. 我 ...