参考学习网址: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(转)的更多相关文章

  1. iOS KVO概述

    iOS KVO概述 面试中经常会被问到:什么是KVO?这个问题既然出现概率这么大,那么我们就来详细讲一讲到底什么是KVO.下次再有面试官问你的时候,你就可以娓娓道来,以彰显高逼格 概述 问:什么是KV ...

  2. iOS:KVO/KVC 的概述与使用

    iOS:KVO/KVC 的概述与使用       KVO   APP开发技术QQ群:347072638 一,概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性 ...

  3. iOS kvo 结合 FBKVOController 的使用

    iOS kvo 结合 FBKVOController 的使用 一:FBKVOControlloer是FaceBook开源的一个 在 iOS,maxOS上使用 kvo的 开源库: 提供了block和@s ...

  4. iOS KVO详解

    一.KVO 是什么? KVO 是 Objective-C 对观察者设计模式的一种实现.[另外一种是:通知机制(notification),详情参考:iOS 趣谈设计模式——通知]: KVO 提供一种机 ...

  5. ios - kvo观察者示例

    首先创建Person分类 #import <Foundation/Foundation.h> @interface Person : NSObject @property (nonatom ...

  6. iOS KVO 学习笔记

    //// //// main.m //// TestBasis //// //// Created by ficow on 16/1/14. //// Copyright © 2016年 ficow. ...

  7. iOS - KVO 键值观察

    1.KVO KVO 是 Key-Value Observing 的简写,是键值观察的意思,属于 runtime 方法.Key Value Observing 顾名思义就是一种 observer 模式用 ...

  8. ios kvo

    kvo的使用方法: 1.注册: -(void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NS ...

  9. iOS KVO的原理

    KVO(Key Value Observing),是观察者模式在Foundation中的实现.   KVO的原理   简而言之就是:   1.当一个object有观察者时,动态创建这个object的类 ...

  10. 【转】 iOS KVO KVC

    原文: http://www.cocoachina.com/industry/20140224/7866.html Key Value Coding Key Value Coding是cocoa的一个 ...

随机推荐

  1. 28-SQLServer带见证服务器的镜像搭建

    一.注意点 1.数据库的模式要是完整模式. 2.要对数据库完整备份和事务日志备份,分别还原到镜像库上,使用NORECOVERY模式. 3.镜像数据库是不允许删除和操作,即便查看属性也不行. 4.先删除 ...

  2. appium问题汇总(持续更新。。。)

    WEBVIEW_unknown adb版本较低,adb 1.0.32版本不支持安卓8.x版本,更新adb版本后正常 Install homebrew ruby -e "$(curl -fsS ...

  3. BZOJ 2699: 更新 (DP)

    题目 对于一个数列A[1-N],一种寻找最大值的方法是:依次枚举A[2]到A[N],如果A[i]比当前的A[1]值要大,那么就令A[1]=A[i],最后A[1]为所求最大值.假设所有数都在范围[1, ...

  4. 黑魔法师之门 (magician)-并查集

    题目 经过了 16 个工作日的紧张忙碌,未来的人类终于收集到了足够的能源.然而在与 Violet 星球的战争中,由于 Z 副官的愚蠢,地球的领袖 applepi 被邪恶的黑魔法师 Vani 囚禁在了 ...

  5. eclipse/myeclipse SVN资源库URL中文乱码问题解决办法

    右击选择资源库地址 可以自定义名称

  6. MongoDB 分片管理(三)服务器管理

    MongoDB 分片管理(三)服务器管理

  7. 链家网爬虫同步VS异步执行时间对比

    异步执行时间 import time import asyncio import aiohttp from lxml import etree start_time = time.time() asy ...

  8. codeforces#1248D2. The World Is Just a Programming Task(括号匹配转化为折线处理)

    题目链接: http://codeforces.com/contest/1248/problem/D2 题意: 可以执行一次字符交换的操作 使得操作后的字符串,循环移位并且成功匹配的方案最多 输出最多 ...

  9. vue移动app扫码功能

    第一步: 上面这段代码写在index.html里面,我也不知道为什么,可能是全局的关系: 第二步: 定义一个按钮,点击启动扫码功能,另外再定义一个盒子来当做扫码的容器:我给这个盒子定义了一个id类名: ...

  10. 【知识点】Java常用类库

    1.字符串 修改字符串内容用StringBuffer,没有“+”,需要用append(),否则用String 2.JVM 相关 Runtime,单例模式,通过getRuntime()获取实例,可以调用 ...