您的位置:首页 > 移动开发 > Objective-C

objective-c介绍之 KVO,KVO,通知

2015-08-21 21:15 417 查看
1、KVC

KVC是一种间接访问对象属性(用字符串表征)的机制,而不是直接调用对象的accessor方法或是点(.)直接访问成员对象的属性。例如访问一个对象属性我们可以person.age
也可以通过kvc的方式 [personvalueForKey:@"age"]
key就是确定对象某个值的字符串,也就是属性的名称,它通常和accessor方法或是变量同名,并且必须以小写字母开头。Keypath就是以“.”分隔的key,因为属性值也能包含属性。比如我们可以person这样的key,也可以有key.gender这样的keypath。

获取属性值时可以通过valueForKey:的方法,设置属性值用setValue:forKey:。与此同时,KVC还对未定义的属性值定义了valueForUndefinedKey:,你可以重载以获取你要的实现(补充下,KVC定义载NSKeyValueCoding的非正式协议里)。注意的是KVC的Value都必须是对象。

在O-C 2.0引入了property,我们也可以通过.运算符来访问属性。下面直接看个例子:

@property NSIntegernumber;

instance.number =3;

[instance setValue:[NSNumber numberWithInteger:3]forKey:@"number"];

以上介绍了通过KVC来获取/设置属性,接下来要说明下实现KVC的访问器方法(accessormethod)。Apple给出的惯例通常是:

-key:,以及setKey:(使用的nameconvention和setter/getter命名一致)。对于未定义的属性可以用setNilValueForKey:。

至此,KVC的基本概念你应该已经掌握了。之所以是基本,因为只涉及到了单值情况,kvc还可以运用到对多关系,这里就不说了,留给各位自我学习的空间。

2、KVO

既然我们能用KVC访问属性,当这个属性的值发生变化时,我们也能很好的监听。当然这个过程系统已经给我们实现了。我们不需要写过多的代码,只需要注册这个监听,就能很好的监听属性的值发生变化。Kvo是Cocoa的一个重要机制,他提供了观察某一属性变化的方法,极大的简化了代码。这种观察-被观察模型适用于这样的情况,比方说根据A(数据类)的某个属性值变化,B(view类)中的某个属性做出相应变化。对于推崇MVC的cocoa而言,kvo应用的地方非常广泛。(这样的机制听起来类似Notification,但是notification是需要一个发送notification的对象,一般是notificationCenter,来通知观察者。而kvo是直接通知到观察对象。)

适用kvo时,通常遵循如下流程:

1 注册:

-(void)addObserver:(NSObject
*)anObserverforKeyPath:(NSString
*)keyPathoptions:(NSKeyValueObservingOptions)optionscontext:(void*)context

keyPath就是要观察的属性值,options给你观察键值变化的选择,而context方便传输你需要的数据(注意这是一个void型)。

options是监听的选项,也就是说明监听泛黄的额字典包含什么值。有两个常用的选项:

NSKeyValueObservingOptionsNew指返回的字典包含新值。

NSKeyValueObservingOptionsOld值返回的字典包含旧值。

2 实现变化方法:

-(void)observeValueForKeyPath:(NSString
*)keyPathofObject:(id)object

change:(NSDictionary *)changecontext:(void*)context

change里存储了一些变化的数据,比如变化前的数据,变化后的数据;如果注册时context不为空,这里context就能接收到。

其实,知道了kvo的逻辑只是帮助你理解而已,要真正掌握的,不在于kvo的实现步骤是什么,而在于KVC,因为只有符合KVC标准的对象才能使用kvo(强烈推荐要使用kvo的人先理解KVC)。

给下面一个例子:

1 .person类
@implementation Person
@synthesize name,age;//属性name 将被监视
-(void) changeName
{
name=@"changeName directly";
}
@end

2.PersonMonitor类 监视了name属性
@implementation PersonMonitor

- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqual:@"name"])
{
NSLog(@"change happen, old:%@ new:%@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey]);
}
}
@end

3测试代码

//初始化被监视对象
Person *p =[[Person alloc] init];
//监视对象
PersonMonitor *pm= [[PersonMonitor alloc]init];
[p addObserver:pm forKeyPath:@"name" options:(NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld) context:nil];

//测试前的数据
NSLog(@"p.name is %@",p.name);

//通过setvalue 的方法,PersonMonitor的监视将被调用
[p setValue:@"name kvc" forKey:@"name"];

//查看设置后的值
NSLog(@"p name get by kvc is %@",[p valueForKey:@"name"]);

//效果和通过setValue 是一致的
p.name=@"name change by .name=";

//通过person自己的函数来更改name
[p changeName];

结果是
输出
2011-07-03 16:35:57.406 Cocoa[13970:903] p.name is name
2011-07-03 16:35:57.418 Cocoa[13970:903] change happen, old:name new:name kvc
2011-07-03 16:35:57.420 Cocoa[13970:903] p name get by kvc is name kvc
2011-07-03 16:35:57.421 Cocoa[13970:903] change happen, old:name kvc new:name change by .name=
最后一次修改是直接修改 所以没法产生通知

3、通知(Notification)

通知是一种发送给一个或者多个观察者,用来通知其在程序中发生了某个事件的消息。Cocoa中的通知机制遵循的是一种广播的模式。它是一种程序中事件的发起者或者是处理者和其他想要知道该事件的对象沟通的一种方式。消息的接收者,也就是观察者响应该事件来变换自己的UI,行为或者是状态。发送通知的对象没有必要知道这些观察者都是谁。因此,通知时一种在程序中可以获得高效协作同时保持较高内聚性的机制。他减少了程序中对象相互之间的强依耐性(这种依耐性会大大降低程序中代码的可复用性)。基础库,AppKit以及其他的一些Objective-C框架中的很多类都定义了通知以便我们可以注册成为通知的观察者。

通知机制的核心就是一个进程中单一实例的对象,被叫做通知中心(NSNotificationCenter)。当一个对象发布一个通知时,通知会先被发布到通知中心。通知中心的作用相当于是交流所,作为通知的广播中心。程序中其他需要感知该事件的对象通过向通知中心注册就可以达到在事件发生时被通知中心及时通知到得目的。通知中心是可以以同步的方式向其观察者发送通知,也是可以通过使用通知队列(NSNotificationQueue)来异步地发送通知。


用于表示通知的对象

一个通知是用NSNotification类的一个对象来表示的。表示通知的对象中含有用于表示该通知的信息的字段:通知的名称,发布通知的对象以及一个用于表示其他补充信息的字典。这个字典被称为是userInfo字典。当通知被发送给对其感兴趣的观察者时,该表示通知的对象会被作为参数传入到处理该通知的方法中。


观察指定的通知

实现观察某个通知的时候,我们先要获取NSNotificationCenter的单实例对象并向其发送addObserver:selector:name:object:消息。通常情况下,这种注册的行为在应用程序启动后就要进行。addObserver:selector:name:object:方法的第二个参数是一个选择器,该选择器指定的是处理指定通知的具体方法。方法的原型必需如下:

-(void)myNotificationHandler:(NSNotification*)notif;

在该方法中,我们可以提取通知中的相关信息来帮助我们处理数据,特别是userInfo中的数据(如果userInfo存在的话)。


发布通知

通常在发布通知之前,我们都需要定义一个全局的字符串常量来作为通知的名称。传统的做法是采用和应用程序相关的两个或者三个字母作为通知名称的前缀,例如:

NSString & AMMyNotification = @”AMMyNotification”;

通过向NSNotificationCenter的单实例对象发送postNotificationName:object:userInfo:(或者类似的)消息来完成通知的发布。在向通知中心发送通知之前,该方法会先创建一个表示该通知的对象。

总结如下:

1、获得通知中心对象
NSNotificationCenter *center=[NSNotificationCenter defaultCenter]; //单例实际是获得通知中心的地址

2、监听通知
[center addObserver :监听者selector:须执行的方法name:所监听者通知的名称object:通知发送者];
3、通知中心发布消息
[centerPostNotificationName:@"国王万岁"object:某人];
4.移除监听中心
[center removeObserver:self name:@"国王万岁"object:某人];

Demo

King *king= [[King alloc]init];
Farmer*farmer = [[Farmer alloc]init];
NSNotificationCenter *center = [NSNotificationCenterdefaultCenter];
[centeraddObserver:farmer selector:@selector(test:) name:@"国王万岁"object:king];
[centerpostNotificationName:@"国王万岁"object:king];
[centerremoveObserver:farmer];
[kingrelease];
[farmerrelease];

-(void)test:(NSNotification*)n //方法必须实现在监听通知的类里面
做想做的事
{
NSLog(@"name:%@ object:%@userInfo:%@",[n
name],[nobject],[n
userInfo]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: