iOS-KVO(转)
参考学习网址:http://blog.sina.com.cn/s/blog_71715bf8010166ut.html
KVO就是NSKeyValueObserving的缩写,它也是Foundation Kit中的一个NSObject的Category,
KVO 基于KVC 实现,基于观察者设计模式(Observer Pattern)实现的一种通知机制,你可以
类比JAVA 中的JMS,通过订阅的方式,实现了两个对象之间的解耦,但又可以让他们相互
调用。
按照观察者模式的订阅机制,KVO 中必然有如下三个方法:
A. 订阅(Subscribe)
- (void) addObserver: (NSObject*) anObserver
forKeyPath: (NSString*) aPath
options: (NSKeyValueObservingOptions) options
context: (void*) aContext;
参数options 为NSKeyValueObservingOptionOld、NSKeyValueObservingOptionNew。
B. 取消订阅(Unsubscribe)
- (void) removeObserver: (NSObject*) anObserver
forKeyPath: (NSString*) aPath;
C. 接收通知(Receive notification)
- (void) observeValueForKeyPath: (NSString*) aPath
ofObject: (id) anObject
change: (NSDictionary*) aChange
context: (void*) aContext;
这三个方法的参数不大容易直接说清楚都是什么意思,下面我们通过实际的代码来理解。这
段代码的业务含义就是警察一直监视犯人的名字是否发生变化,只要发生变化,警察就会收
到通知。
#import <Foundation/Foundation.h>
//犯人类型
@interface Prisoner: NSObject{
int pid;
NSString *name;
}
-(void) setPid: (int) pid;
-(void) setName: (NSString*) name;
-(int) pid;
-(NSString*) name;
@end
@implementation Prisoner
-(void) setPid: (int) p{
pid=p;
}
-(void) setName: (NSString*) n{
[n retain];
[name release];
name=n;
}
-(int) pid{
return pid;
}
-(NSString*) name{
return name;
}
-(void) dealloc{
[name release];
[super dealloc];
}
@end
//警察类型
@interface Police: NSObject
@end
@implementation Police
//接收通知的方法,继承自NSObject 父类。
//请先看main 函数中的addObserver 方法参数的解释再来这个方法的解释。
//第一个参数是你监视的对象上的属性,第二个参数是你监视的对象,第三个参数存放了你
监视的属性的值,最后一个参数我们传递nil。
- (void) observeValueForKeyPath: (NSString*) aPath
ofObject: (id) anObject
change: (NSDictionary*) aChange
context: (void*) aContext{
if([aPath isEqualToString: @"name"]){
NSLog(@"Police : %@",[aChange objectForKey: @"old"]);
NSLog(@"Police : %@",[aChange objectForKey: @"new"]);
//因为main 函数中我们监听name 的新旧两个值,所以aChange 这个字典对
象里就存放了@”old”、@”new”两个key-value 对。
}
}
@end
int main (int argc , const char * argv[]){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Prisoner *prisoner=[[Prisoner alloc] init];
Police *police=[[Police alloc] init];
//为犯人添加观察者警察,警察关注犯人的name 是否发生变化,如果发生变化就立即
通知警察,也就是调用Police 中的observeValueForKeyPath 方法。
//换句话说就是警察对犯人的名字很感兴趣,他订阅了对犯人的名字变化的事件,这个
事件只要发生了,警察就会收到通知。
[prisoner addObserver: police
forKeyPath: @"name"
options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context: nil];
//addObserver 的调用者是要被监视的对象,第一个参数是谁要监视它,第二个参数是
监视它的哪个属性的变化(使用KVC 机制,也就是前面所说的KVO 基于KVC),第三个参
数是监视属性值改变的类型,我们这里监听Old、New,也就是Cocoa 会把name 属性改变
之前的旧值、改变之后的新值都传递到Police 的处理通知的方法,最后一个参数我们传递
nil。
//这里有一个陷阱,如果你不小心把forKeyPath 的属性名写错了,prisoner 里根本就不
存在, 那么Cocoa 不会报告任何的错误。所以当你发现你的处理通知的
observeValueForKeyPath 没有任何反应的时候,首先看一下是不是这个地方写错了。
[prisoner setName: @"豆豆"];
//警察取消订阅犯人名字变化的事件。
[prisoner removeObserver: police
forKeyPath: @"name"];
[prisoner setName: @"太狼"];
[prisoner release];
[police release];
[pool release];
return 0;
}
运行之后,Shell 窗口输出:
2011-04-01 15:20:33.467 Kvo[2004] Police : <null>//因为name 没有old 值
2011-04-01 15:09:18.479 Kvo[4004] Police : 豆豆
Notification 是Objective-C 中的另一种事件通知机制,依然以犯人、警察的示例进行演
示。
#import <Foundation/Foundation.h>
//犯人类型
@interface Prisoner: NSObject{
int pid;
NSString *name;
}
-(void) setPid: (int) pid;
-(void) setName: (NSString*) name;
-(int) pid;
-(NSString*) name;
@end
@implementation Prisoner
-(void) setPid: (int) p{
pid=p;
}
-(void) setName: (NSString*) n{
[n retain];
[name release];
name=n;
}
-(int) pid{
return pid;
}
-(NSString*) name{
return name;
}
-(void) dealloc{
[name release];
[super dealloc];
}
@end
//警察类型
@interface Police: NSObject
-(void) handleNotification:(NSNotification *) notification;
@end
@implementation Police
-(id) init{
self=[super init];
if(self){
//获取通知中心,它是单例的。
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
//向通知中心把自己添加为观察者,第一个参数是观察者,也就是警察自己,
第二个参数是观察的事件的标识符prisioner_name,这就是一个标识性的名字,不是特指哪
一个属性,第三个参数指定handleNotification 为处理通知的方法。
[nc addObserver: self selector:@selector(handleNotification:)
name:@" prisioner_name" object:nil];
}
}
//接收通知,这个方法的名字任意,只有参数是Notification 就可以了。
-(void) handleNotification:(NSNotification *) notification{
Prisoner *prisoner=[notification object];//获得通知中心传递过来的事件源对象
NSLog(@"%@",[prisoner name]);
}
@end
int main (int argc , const char * argv[]){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Prisoner *prisoner=[[Prisoner alloc] init];
Police *police=[[Police alloc] init];
[prisoner setName: @"豆豆"];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
//向通知中心发送通知,告知通知中心有一个prisioner_name 的事件发生了,并把自
己作为事件源传递给通知中心。
//通知中心随后就会查找是谁监听了prisioner_name 事件呢?找到之后就调用观察者
指定的处理方法,也就是Police 中的handleNotification 方法被调用。
[nc postNotificationName: @"prisioner_name" object: prisoner];
//从通知中心移除观察者
[nc removeObserver: police];
[prisoner setName: @"太狼"];
[prisoner release];
[police release];
[pool release];
return 0;
}
Shell 窗口输出如下所示:
2011-04-01 16:20:58.995 Notification[2564] 豆豆
我们看到这种通知方式的实现非常不优雅,观察者Police 中耦合了通知中心的API,而且最
重要的是看到红色的一行代码了吗?通知的发送是需要被监视的对象主动触发的。
iOS-KVO(转)的更多相关文章
- iOS KVO概述
iOS KVO概述 面试中经常会被问到:什么是KVO?这个问题既然出现概率这么大,那么我们就来详细讲一讲到底什么是KVO.下次再有面试官问你的时候,你就可以娓娓道来,以彰显高逼格 概述 问:什么是KV ...
- iOS:KVO/KVC 的概述与使用
iOS:KVO/KVC 的概述与使用 KVO APP开发技术QQ群:347072638 一,概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性 ...
- iOS kvo 结合 FBKVOController 的使用
iOS kvo 结合 FBKVOController 的使用 一:FBKVOControlloer是FaceBook开源的一个 在 iOS,maxOS上使用 kvo的 开源库: 提供了block和@s ...
- iOS KVO详解
一.KVO 是什么? KVO 是 Objective-C 对观察者设计模式的一种实现.[另外一种是:通知机制(notification),详情参考:iOS 趣谈设计模式——通知]: KVO 提供一种机 ...
- ios - kvo观察者示例
首先创建Person分类 #import <Foundation/Foundation.h> @interface Person : NSObject @property (nonatom ...
- iOS KVO 学习笔记
//// //// main.m //// TestBasis //// //// Created by ficow on 16/1/14. //// Copyright © 2016年 ficow. ...
- iOS - KVO 键值观察
1.KVO KVO 是 Key-Value Observing 的简写,是键值观察的意思,属于 runtime 方法.Key Value Observing 顾名思义就是一种 observer 模式用 ...
- ios kvo
kvo的使用方法: 1.注册: -(void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NS ...
- iOS KVO的原理
KVO(Key Value Observing),是观察者模式在Foundation中的实现. KVO的原理 简而言之就是: 1.当一个object有观察者时,动态创建这个object的类 ...
- 【转】 iOS KVO KVC
原文: http://www.cocoachina.com/industry/20140224/7866.html Key Value Coding Key Value Coding是cocoa的一个 ...
随机推荐
- Java中String、StringBuilder和StringBuffer
StringBuilder和StringBuffer内部都是通过char[]来实现的.(jdk1.9后,底层把char 数组变成了byte[].)唯一不同的就是我们的StringBuffer内部操作方 ...
- google Guava包的reflection(反射)解析
译者:万天慧(武祖) 由于类型擦除,你不能够在运行时传递泛型类对象——你可能想强制转换它们,并假装这些对象是有泛型的,但实际上它们没有. 举个例子: ArrayList<String> s ...
- dumpe/dumpe2fs/e2fsck
xt2/3/4文件系统备份工具 导出ext2/ext3/ext4文件系统信息 dumpe2fs e2fsck 强制检查文件系统 检查文件系统
- svg创建分支
是这样的 我之前的项目上传到svn上一直没有开过分支,今天其中的一个项目改动会比较大,想创建一个分支,在此分支上修改(目的是改动如果比较大,不想影响原来主干上的分支) 首先打开我们的项目存放的文件:右 ...
- Python测试框架对比
如有任何学习问题,可以添加作者微信:lockingfree 更多学习资料请加QQ群: 822601020获取 unittest, pytest, nose, robot framework对比 什么是 ...
- [bzoj 5332][SDOI2018]旧试题
传送门 Description \[ \sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^Cd(ijk) (\mathrm{mod\:} 10^9+7) \] 其中 \(d(ijk) ...
- C++标准库分析总结(四)——<Vector、Array、Forward_list设计原则>
本节主要总结标准库Vector和Array的设计方法和特性以及相关迭代器内部特征 1.Vector 1.1 Vector 内部实现 Vector是自增长的数组,其实在标准库中没有任何一种容器能原地扩充 ...
- zabbix (6) 为主机添加监控项,触发器,动作
先了解一下zabbix的相关概念 监控项(iterms):一个具体的指标,比如某个人的体重. 键(key):通过定义(自定义或者zabbix自带)的key获取相应指标的具体值,比如这个人的体重50斤 ...
- 深度解读Facebook刚开源的beringei时序数据库——数据压缩delta of delta+充分利用内存以提高性能
转自:https://yq.aliyun.com/topic/58?spm=5176.100239.blogcont69354.9.MLtp4T 摘要: Facebook最近开源了beringei时序 ...
- 微信小程序开发步骤简述
1.登陆微信的开发这平台 2.找到小程序开发选项进入,填写注册自己的小程序信息 3.下载相应的开发者工具 4.通过开发者工具把自己的项目代码上传,上传时会让你填写自己小程序的appid这样项目代码就和 ...