iOS学习之KVO的使用
来源:互联网 发布:windows md文件编辑器 编辑:程序博客网 时间:2024/04/27 21:33
坚持 成长 每日一篇
在MVC的设置模式下,Model块要通知到Control块的通信我们往往采用的“盲”通信(即不知道对方是什么对象),这个时候我们往往采用的是KVO和Notification,这两者其实是极其相似的。KVO符合了观察者设计模式。
KVO的注册,解除,回调函数
当我们要对model的某个属性添加观察者,可以通过addObserver方法
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
解除观察者用
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
观察者回调函数,else是把当前不能处理的key值转给父类处理,@”_model”必须是addserver时候传入的字符串,由于字符串的存储的内存的位置栈里,所以此处的==可以成立,如果你传递的是对象的话需要另行处理
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if (context == @"_model") { NSLog(@"key = %@,dic = %@",keyPath,change); } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; }}
注意:addObeserver时候最好使用字符串常量,否则就通过key来判断。
我们使用Notification时候,可以通过post来通知观察者作出回调,那么KVO的post类型可以分为两种,一种是系统自动完成post代码添加和我们手动完成post代码加添,我们称为自动实现KVO和手动实现KVO
自动实现KVO
NSObject,NSArray,NSSet均实现了addOberserver和removeOberserverf方法,因此我们不仅可以观察普通对象,还可以观察数组或结合类对象。
当我们使用addOberserver时候,系统自动帮添加了post代码
[model addObserver:observer forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@“model”];
当model对象的全局调用setAge:给_age或者age全局变量赋值时候会自动通知观察者(即自动post)
注意:如果setAge里面操作的不是名为age或_age全局变量,且没有通过@synthesize age = _name;来转化控制会crash,使用synthesize会对一个全局变量添加两个监控key值
自动实现KVO只有通过KVC,属性赋值,和set方法背掉用时候会触发post(其实最终都是走set方法)
手动实现KVO
自动实现KVO只有依赖set方法来触发,如果我们在一个方法里面通过如下方式给model的_name全局变量赋值
-(void)upLoad{ _name = @"张三";}
这时候我们的Model发生了改变,但是自动实现KVO并不会通知观察者属性发生变化,如果我们要通知观察者属性发生变化需要加入下面两行代码
-(void)upLoad{ [self willChangeValueForKey:@"name"]; _name = @"张三"; [self didChangeValueForKey:@"name"];}
注意:手动KVO和自动KVO不能同时用,即不能在set方法下加入手动KVO,否则会引起两次KVO函数回调
如果你非要这么做的话,可以在automaticallyNotifiesObserversForKey类方法里面屏蔽对某个key的自动KVO,这样就不会引起观察者两次回调KVO函数
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key { if ([key isEqualToString:@"name"]) { return NO; } return [super automaticallyNotifiesObserversForKey:key];}
这里注意:对其它非手动实现的 key,要转交给 super 来处理。
依赖键
一个model可以拥有其他model对象,当我们这个model对象的某个属性如name发生变化时候,我们又如何通知观察者呢,因此Object引入了依赖键
在model的实现文件下添加如下代码
- (NSString *)information{ return [[NSString alloc] initWithFormat:@"%@#%@", [_personModel name], [_personModel infomation]];}- (void)setInformation:(NSString *)theInformation{ NSArray * array = [theInformation componentsSeparatedByString:@"#"]; _personModel.name = array[0]; _personModel.infomation = array[1];}+(NSSet*)keyPathsForValuesAffectingInformation{ return [NSSet setWithObjects:@"personModel.name",@"personModel.infomation", nil];}//+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key//{// NSSet * keyPaths = [super keyPathsForValuesAffectingValueForKey:key];// NSArray * moreKeyPaths = nil;//// if ([key isEqualToString:@"personModel"])// {// moreKeyPaths = [NSArray arrayWithObjects@"personModel.name",@"personModel.infomation", nil];// }//// if (moreKeyPaths)// {// keyPaths = [keyPaths setByAddingObjectsFromArray:moreKeyPaths];// }// // return keyPaths;//}
使用例子
[_model addObserver:self forKeyPath:@"information" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"_model"]; _model.personModel = [[PersonModel alloc] init]; _model.personModel.name = @"李四"; _model.personModel.infomation = @"福建人";
观察者回调函数
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if (context == @"_model") { NSLog(@"key = %@,dic = %@",keyPath,change); } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; }}
控制台输出结果如下
2015-12-25 15:09:13.479 KVO学习Demo[13788:6671887] key = information,dic = { kind = 1; new = "\U674e\U56db#(null)"; old = "(null)#(null)";}2015-12-25 15:09:13.479 KVO学习Demo[13788:6671887] key = information,dic = { kind = 1; new = "\U674e\U56db#\U798f\U5efa\U4eba"; old = "\U674e\U56db#(null)";}
每次personModel的属性值发生变化都会引起回调函数回调
KVO的底层实现
KVO底层实现机制才用了Runtime机制,大致原理是在掉用addServer时候系统会根据模型类创建一个观察者类来替换原来的类,然后把原来的类对象的isa指向新创建的类里。有兴趣的同学可以看下面的文章,或问度娘,谷哥。。。
http://blog.csdn.net/kesalin/article/details/8194240
总结:KVO简单的页面逻辑使用还想,复杂了不好用,最好自己写一KVO类似的机制来通信
- iOS学习之KVO的使用
- iOS之KVO使用
- 【IOS学习】KVO的使用,demo
- [ios开发基础之]KVO的使用
- IOS开发之----KVO的使用
- iOS学习之KVO、KVC
- iOS中KVO的使用
- ios KVC KVO的使用
- ios KVO的简单使用
- IOS学习笔记之KVC、KVO
- 【ios】iOS:KVO的概述与使用
- IOS之KVO使用问题(一)
- iOS中KVO,KVC的学习记录
- iOS中KVO,KVC的学习记录
- iOS中键值监听KVO的学习
- iOS的观察者模式之:KVC&KVO
- iOS之KVO模式的相关内容
- iOS 开发之KVO的底层实现
- QT 窗口设置可拉伸背景图
- 安卓WebView与ScrollView嵌套大面积空白解决小技巧和适配
- IOS系列教程
- RSA加密解密
- 二叉树的建树、遍历(先序、中序、后序、层次)(递归和非递归)--Java实现
- iOS学习之KVO的使用
- 【cocos2d-x】之添加虚拟摇杆
- Java WebService 简单实例
- iOS 绘图机制简介,Quartz 2D绘图用CGContextRef绘制音频波形图 —— HERO博客
- android内部空间写文档
- Android 毛玻璃效果弹出菜单动画
- IntelliJ IDEA15在线激活服务器地址
- 用wamp打开进入localhost,但是无法打开localhost中的文件夹
- Mybatis3源码分析(18)-插件(plugins)拦截器