KVO与KVC
简介
KVC(Key–Value Coding,键值编码)KVC提供了一种在运行时而非编译时动态访问对象属性与成员变量的方式,也就是说,我们可以用字符串的内容作为属性名称或者成员变量名称进行访问。这种特性有些类似于其他高级编程语言中的反射(比如java)。简单的说它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。
KVO(Key-Value Observing,键值观察)KVO提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
今天看了下KVC与KVO的相关东西,突然有了一种醍醐灌顶的感觉,以前没用过,但是今天才发现,这是个好东西啊,以前要是我们的界面上面有关于UI的变动,我们必须要对界面进行刷新后才能看到效果,然而每次的刷新必定会带来很大的内存开销,特别是我们使用UIViewTable的时候,要是数据变更多了,那么我们就需要重新处理变更所带来的界面变化,那么我们又会重新去加载cell,要是cell达到了几百的数量级,那么我么的内存实际上是需要很大的开销的,有了KVC、KVO这个问题就迎刃而解了,我们可以在可能需要变化的属性上面注册KVO,当我们的界面发生改变的时候,直接可以改变属性值,而不需要我们再次使用刷新的方式来更新界面了。
在说使用KVO的时候,我想先说说KVC,因为我们要想使我们的KVO得到有效的使用,我们的对象必须是建立在支持KVC的基础之上的,先不扯淡了,我们直接进入正题吧。
KVC使用
关键方法所在协议:NSKeyValueCodingprotocol
KVC支持类对象和内建基本数据类型。
1.获取值方法
valueForKey:,传入NSString属性的名字。
valueForKeyPath:,传入NSString属性的路径,xx.xx形式。
valueForUndefinedKey它的默认实现是抛出异常,可以重写这个函数做错误处理。
2.修改值方法
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:
setNilValueForKey: 当对非类对象属性设置nil时,调用,默认抛出异常。
3.一对多关系成员的情况
mutableArrayValueForKey:有序一对多关系成员 NSArray
mutableSetValueForKey:无序一对多关系成员 NSSet
KVC使用案例
|
|
结果:testPerson‘s init height = 0; testPerson‘s height =173;
注意:
(1). key的值必须正确,如果拼写错误,会出现异常
(2). 当key的值是没有定义的,valueForUndefinedKey:这个方法会被调用,如果你自己写了这个方法,key的值出错就会调用到这里来
(3). 因为类key反复嵌套,所以有个keyPath的概念,keyPath就是用.号来把一个一个key链接起来,这样就可以根据这个路径访问下去比如:
Person p = [[Person alloc] init];
NSString personsName = [p valueForKey:@”height”];
NSString *spousesName = [p valueForKeyPath:@”spouse.height”];
key 与 key pat 要区分开来,key 可以从一个对象中获取值,而 key path 可以将多个 key 用点号 “.” 分割连接起来比如
[p valueForKeyPath:@”spouse.height”]等价于[[p valueForKey:@”spouse”] valueForKey:@”height”];
(4). NSArray/NSSet等都支持KVC
KVO使用
KVO使用起来也是非常简单,其实这样的机制听起来类似Notification,但是Notification是需要一个发送Notification的对象,一般是NotificationCenter,来通知观察者。而KVO是直接通知到观察对象,使用KVO分三步,注册-实现-必要时取消观察。
1.注册需要观察的对象的属性addObserver:forKeyPath:options:context:
2.实现observeValueForKeyPath:ofObject:change:context:方法,这个方法当观察的属性变化时会自动调用
3.取消注册观察removeObserver:forKeyPath:context:
KVO使用案例
这里使用一个例子,我再网上看到感觉对于理解KVO非常有帮助iOS:KVO/KVC 的概述与使用
假设一个场景,股票的价格显示在当前屏幕上,当股票价格更改的时候,实时显示更新其价格。
1.定义DataModel
2.定义此model为Controller的属性,实例化它,监听它的属性,并显示在当前的View里边
3.当点击button的时候,调用buttonAction方法,修改对象的属性
- 实现回调方法1234567-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{if([keyPath isEqualToString:@"price"]){myLabel.text = [stockForKVO valueForKey:@"price"];}}
5.增加观察与取消观察是成对出现的,所以需要在最后的时候,移除观察者
KVO这种编码方式使用起来很简单,很适用与数据模型修改后,引发的UIVIew的变化这种情况,就像上边的例子那样,当更改属性的值后,监听对象会立即得到通知。
注意: 需要强调的是KVO的回调要被调用,属性必须是通过KVC的方法来修改的,如果是调用类的其他方法来修改属性,这个观察者是不会得到通知的。
KVC最佳实践
接下来,我们要以集合为例,来对掌握的KVC进行一下实践。
之所以选择array,因为在ios中,array往往做为tableview的数据源,有这样的一种情况:
假设我们已经有N条数据,在进行了某个操作后,有在原先的数据后多了2条记录;或者对N中的某些数据进行更新替换。不使用KVC我们可以使用 reloadData方法或reloadRowsAtIndexPaths。前一种的弊端在于如果N很大消耗就很大。试想你只添加了几条数据却要重载之前 N数据。后一种方法的不足在于代码会很冗余,你要一次计算各个indexPath再去reload,而且还要提前想好究竟在哪些情况下会引起数据更新,倘若使用了KVC/kvo,这样的麻烦就迎刃而解了,你将不用关心追加或是更新多少条数据。