键值观察(KVO)是基于键值编码的一种技术。

利用键值观察可以注册成为一个对象的观察者,在该对象的某个属性变化时收到通知。

被观察对象需要编写符合KVC标准的存取方法,编写键值观察分为以下三步:

(1)注册成为观察者。

(2)定义KVO的回调。

(3)移除观察者。

+新建一个类Student,属性为name,age。

@interface Student : NSObject
@property(copy,nonatomic) NSString * name;
@property(nonatomic) int age;
@end

新建一个Parent类,作为观察者。main函数:

    Student * student = [Student new];
Parent * parent = [Parent new];
//建立观察者模式关系,注册观察者
[student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
[student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];

第一个参数:(student)被观察者。

第二个参数:(parent)观察者。

第三个参数:(forKeyPath)键路径参数,要观察的键路径,这里观察name和age。

第四个参数:(options)标识KVO希望变化如何传递给观察者,可以使用|进行多选,这里观察变化的新值和旧值。

第五个参数:上下文内存区,通常为nil

+在parent.m的文件中定义KVO的回调。

@implementation Parent
//观察者实现键值观察方法,要作为观察者,需要实现这个方法。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
id newValue = [change objectForKey:NSKeyValueChangeNewKey];
NSLog(@"家长观察对象:对象:%@的属性%@的值发生了改变,旧值为:%@,新值为:%@",object,keyPath,oldValue,newValue);
}

其中change是一个字典。

+如果student的name或age发生变化(最后要移除观察者):

    Student * student = [Student new];
Parent * parent = [Parent new];
//建立观察者模式关系,注册观察者
[student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
[student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
student.age = ;
student.name = @"小明";
//结束之前需要移除观察者
[student removeObserver:parent forKeyPath:@"age"];
[student removeObserver:parent forKeyPath:@"name"];

那么parent上定义的的回调会自动执行,打印结果:

当然也可以多个对象观察一个对象,新建teacher类,这样就有两个观察者:

    Student * student = [Student new];
Parent * parent = [Parent new];
Teacher * teacher = [Teacher new];
//建立观察者模式关系,注册观察者
[student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
[student addObserver:teacher forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; [student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
student.age = ;
student.name = @"小明";
//结束之前需要移除观察者
[student removeObserver:parent forKeyPath:@"age"];
[student removeObserver:parent forKeyPath:@"name"];
[student removeObserver:teacher forKeyPath:@"age"];

****************************************

另外一种情况:新建Family类,让student成为它的一个属性,然后让Family成为student的观察者,这样注册观察者的方法可以写在Family的init方法中,移除观察者写在Family的dealloc方法中:

Family.h文件:

@interface Family : NSObject
@property(strong,nonatomic) Student * student;
-(id) initWithStudent:(Student *)student;
@end

Family.m文件:

@implementation Family
-(id)initWithStudent:(Student *)student
{
if(self = [super init]){
self->_student = student;
//让当前对象成为student的观察者
[self->_student addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:nil];
}
return self;
} //观察者实现键值观察方法,要作为观察者,需要实现这个方法。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{ id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
id newValue = [change objectForKey:NSKeyValueChangeNewKey];
NSLog(@"家庭观察对象:对象:%@的属性%@的值发生了改变,旧值为:%@,新值为:%@",object,keyPath,oldValue,newValue);
} -(void)dealloc
{
NSLog(@"Family dealloc...");
//移除观察者
[self->_student removeObserver:self forKeyPath:@"name"]; //ARC所以不用写super dealloc
}
@end

main:

    Student * student = [Student new];
Family * family = [[Family alloc]initWithStudent:student];
student.name = @"hehe";

可以看到KVO的方式耦合度较高,类之间有直接的关系。接下来看通知。

自定义通知

通知是iOS开发框架中的一种设计模式,通知一般用于M、V、C之间的信息传递。比如设置页面、设置App皮肤。

NSNotification

使用通知之前,我们要创建通知对象。 Notification对象有两个重要的成员变量: name 和 object。一般name用来唯一标示一个通知对象,object指通知发送者。

Notification对象包含一个参数,就是字典(可选参数),这个字典中存储一些传值过程中的信息,供接收者使用。系统要求这个参数是不可变字典。

NSNotificationCenter

通知创建好后就可以在必要的时候发送通知,发送通知的时候,需要一个控制中心来发送通知,这个控制中心就是通知中心。

通知中心是通知机制架构的大脑。它允许我们注册通知监听者、发送通知、移除通知监听者。

一般系统通知不需要我们发送通知。只需要我们注册通知监听者、 移除通知监听者。比如监听视频是否播放完成。

栗子,Teacher发送通知。学生接收:

页面结构:

老师有一个发送方法。Teacher.h文件:

@interface Teacher : NSObject
- (void) sendMessage;
@end

Teacher.m文件:

#import "MacroDefinition.h"
@implementation Teacher
- (void)sendMessage
{
NSNotification * myNotification = [NSNotification notificationWithName:kMyNotificationName object:self userInfo:@{@"content":@"同学们,星期一放假,不用来了"}];
//发送通知
//需要使用通知中心来发送。
//通知中心是一个单例模式的
NSNotificationCenter * center = [NSNotificationCenter defaultCenter];
[center postNotification:myNotification];
}
@end

其中NSNotification中的notificationWithName因为别的地方也会用到,所以写成了宏定义放到了单独的.h文件MacroDefinition中,文件中写了:#define kMyNotificationName @"customNotification" 。userinfo是一个字典,可以存通知的内容。

先写上Student的接收通知后的回调方法:

Student.h文件:

@interface Student : NSObject
//可以跟一个参数,但是只能是NSNotification对象。
-(void)receiveMessage:(NSNotification *) notification;
@end

Student.m文件:

@implementation Student
- (void)receiveMessage:(NSNotification *)notification
{
NSLog(@"对象%@发出来名称为:%@的通知,附加数据为:%@",notification.object,notification.name,[notification.userInfo objectForKey:@"content"]);
}

main引入:

#import "MacroDefinition.h"
#import "Teacher.h"
#import "Student.h"

        Teacher * teacher = [Teacher new];
Student * student1 = [Student new];
Student * student2 = [Student new];
Student * student3 = [Student new];
//订阅通知中心
NSNotificationCenter * center = [NSNotificationCenter defaultCenter];
//注册,第一个参数是观察者,第二个参数是观察者拿到自己关心的通知之后,所要调用的方法,第三个参数为观察者关心的通知的名称,第四个参数为观察者关心的发出对象。
[center addObserver:student1 selector:@selector(receiveMessage:) name:kMyNotificationName object:nil];
[center addObserver:student2 selector:@selector(receiveMessage:) name:kMyNotificationName object:nil];
[center addObserver:student3 selector:@selector(receiveMessage:) name:kMyNotificationName object:nil];
//发送
[teacher sendMessage];
//道理上来说应该移除订阅者
[center removeObserver:student1 name:kMyNotificationName object:nil];
[center removeObserver:student2 name:kMyNotificationName object:nil];
[center removeObserver:student3 name:kMyNotificationName object:nil];

打印结果:

通知中心是一个单例模式的,所以kMyNotificationName,main和Teacher.m中的是同一个,所以这两个文件用的宏定义是一样的。

这样这两个类并没有直接的关系只是通过通知中心来传递消息。关于通知的更多内容后边再补充吧=。=

KVO和通知的区别:

1:KVO的类是由直接联系的,耦合度较高。而通知是没有直接联系的。

2:KVO是只要属性发生改变,观察者就会被响应。通知是被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用也更灵活。

Object-C — KVO & oc通知的更多相关文章

  1. 一句代码,更加优雅的调用KVO和通知

    来源:wazrx 链接:http://www.jianshu.com/p/70b2503d5fd1 写在前面 每次使用KVO和通知我就觉得是一件麻烦的事情,即便谈不上麻烦,也可说是不方便吧,对于KVO ...

  2. KVO和通知中心

    苹果其实在语言层面为我们做了很多事,比如Category实现装饰模式的意图,target-action实现命令模式意图等等,对于观察者模式,苹果也提供了KVO和通知中心,给开发者提供了极大的便利. 观 ...

  3. OC 观察者模式(通知中心,KVO)

    OC 观察者模式(通知中心,KVO) 什么是观察者模式??? A对B的变化感兴趣,就注册为B的观察者,当B发生变化时通知A,告知B发生了变化.这就是观察者模式. 观察者模式定义了一种一对多的依赖关系, ...

  4. OC中另外的一个常用技术:通知(Notification)

    OC中另外的一个常用技术:通知(Nofitication)其实这里的通知和之前说到的KVO功能很想,也是用于监听操作的,但是和KVO不同的是,KVO只用来监听属性值的变化,这个发送监听的操作是系统控制 ...

  5. QF——OC中的KVC,KVO

    KVC: (Key Value Coding) 键值编码 所谓KVC,其实就是不通过set和get方法访问对象属性,而是通过属性名字符串动态的去读取属性.KVC其实也是OC反射机制的一种运用. 之所以 ...

  6. 深入剖析通知中心和KVO

    深入剖析通知中心和KVO 要先了解KVO和通知中心,就得先说说观察者模式,那么观察者模式到底是什么呢?下面来详细介绍什么是观察者模式. 观察者模式 -A对B的变化感兴趣,就注册成为B的观察者,当B发生 ...

  7. iOS开发——UI进阶篇(五)通知、代理、kvo的应用和对比,购物车

    一.通知 1.通知中心(NSNotificationCenter)每一个应用程序都有一个通知中心(NSNotificationCenter)实例,专门负责协助不同对象之间的消息通信任何一个对象都可以向 ...

  8. iOS 之单例,代理,通知,KVO,Block全能解析

    //单例 //.h + (Instannce *)shareInstance; //.m static Instannce *instance = nil; @implementation Insta ...

  9. KVO & 通知 小记

    KVO的全称是Key-Value Observing,它实现了一种机制,对所关心的属性对象添加观察者,当属性值发生变化时会得到通知,我们可以对变化做相应的处理.看过设计模式的同学应该知道,这是一种典型 ...

随机推荐

  1. RatingBar设置显示星星个数

    RatingBar评分控件 项目中遇到问题 marker一下: 关于自定义以及遇到的出现模糊情况 多半是因为切得图除颜色外 不一致的原因 如果大小也不一样,(沃日) 问题是这样的: 我可以通过OnRa ...

  2. IIS短文件漏洞修复

    近期网站系统被扫描出漏洞:IIS短文件/文件夹漏洞 漏洞级别:中危漏洞 漏洞地址:全网站 漏洞描述:IIS短文件名泄露漏洞,IIS上实现上存在文件枚举漏洞,攻击者可利用此漏洞枚举获取服务器根目录中的文 ...

  3. Red5空项目的理解

    在经过三天的苦恼之后,我终于对Red5的工作流程有点了解了.这样一来对要做的项目总算不会太瞎了.出于个人感受,认为下面所讲述的内容对初学者理解Red5以及基于Red5开发有很大的帮助,因此记录下来. ...

  4. JavaScript高级程序设计43.pdf

    事件类型 Web浏览器中有很多事件类型,“DOM3级事件”规定了以下几类事件 UI事件(用户界面),当用户与页面上的元素交互时触发: 焦点事件,当元素获得或失去焦点时触发 鼠标事件,当用户通过鼠标在页 ...

  5. C语言练习题_北理工的恶龙

    背景:最近,北理工出现了一只恶龙,它长着很多 头,而且还会吐火,它将会把北理工烧成废墟, 于是,校长下令召集全校所有勇士杀死这只恶龙.要杀死这只龙,必须把它所有的头都砍掉,每个勇士只能砍一个龙头,龙的 ...

  6. 安卓开发无法识别手机原因之一:手机SDK比工程要求的最小SDK低

      创建工程时,设置限制的最小SDK:   如果你手机的内核版本比你工程的设置的最小SDK低,则不显示   来自为知笔记(Wiz)

  7. 【转】如何实现一个malloc

    任何一个用过或学过C的人对malloc都不会陌生.大家都知道malloc可以分配一段连续的内存空间,并且在不再使用时可以通过free释放掉.但是,许多程序员对malloc背后的事情并不熟悉,许多人甚至 ...

  8. MyEclipse中Web项目的发布和运行

    1.右键对应项目的名称:MyEclipse|Add and Remove Project Deployments... 2.点击Add按钮,选择Tomcat7.x,Deploy type选择Explo ...

  9. typeahead使用配置参数。

    示例代码: var suggestion_source = new Bloodhound({ datumTokenizer: Bloodhound.tokenizers.obj.whitespace( ...

  10. Unity3D中Prefab

    Prefab概念: Prefab是一种资源类型--存储在项目视图中的一种可反复使用的游戏对象.因而当游戏中须要非常多反复使用的对象.资源等时,Prefab就有了用武之地.它拥有下面特点: 能够放到多个 ...