KVC键值编码
一,概述
KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。它在控制层和模型层之间的消息沟通中发挥很大作用。controller层的对象观察model层对象的属性,从而使得view对象可以通过controller层间接观察model的属性,解耦model和view。
例如demo工程IOSKvoUse
初始化:model对象将当前的viewController作为自己score属性的观察者。
1,在viewController中
?
[m_studentKVO addObserver:selfforKeyPath:@m_stuScoreoptions:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];
?
2,用户点击界面的button按钮,会使得model数据改变。
?
[m_studentKVO setValue:[NSStringstringWithFormat:@%d,score]forKey:@m_stuScore];
?
3, 由于viewController注册成为观察者,故而观察者的observeva lueForKeyPath会被调用,通知viewControllermodel数据被更新了。
4, 在观察者的回调方法中,可以刷新相应的界面。
?
if([keyPath isEqualToString:@m_stuScore])
{
m_lable.text = [NSStringstringWithFormat:@score:%@, [m_studentKVOvalueForKey:@m_stuScore]];
}
?
?
二,KVO图解
1. 需要确定是否有KVO的场景,即是否有一个对象需要通知它的属性的改变到另一个对象。
PersonObject 需要知晓BankObject的属性accountBalance 的任何改变 .
2. PersonObject 必须将自己注册成为 BankObject的 accountBalance 属性的观察者。通过发送addObserver:forKeyPath:options:context:消息.
3. 观察者通过实现 observeva lueForKeyPath:ofObject:change:context: 方法对属性改变通知进行回应. 在这个方法中进行你的通知回应的个性化操作。如果父类实现了此方法,那么请注意在方法的最后调用父类的方法。
?
4. 如果你遵循KVO编程逻辑,那么 observeva lueForKeyPath:ofObject:change:context: 方法会被自动调用。
?
三,使用方法
系统框架已经支持KVO,使用异常简单。
l 注册观察者:
?
- (void)registerAsObserver {
/*
Register 'inspector' to receive change notifications for the openingBalance property of
the 'account' object and specify that both the old and new values of openingBalance
should be provided in the observe… method.
*/
[account addObserver:inspector
forKeyPath:@openingBalance
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
}
接收通知
addObserver:forKeyPath:options:context:
方法不会对观察者,被观察者,以及
context
进行任何的强引用,
也就是说它们的生命周期需要你自己保证。
?
返回一个change词典:
1, NSKeyValueChangeKindKey
普通属性改变:NSKeyValueChangeKindKey 返回NSKeyValueChangeSetting
集合对象改变: NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, 或者 NSKeyValueChangeReplacement。
?
2, NSKeyValueChangeOldKey
返回对象属性改变前的值
3, NSKeyValueChangeNewKey
返回属性改变后的值
?
- (void)observeva lueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqual:@openingBalance]) {
[openingBalanceInspectorField setObjectValue:
[change objectForKey:NSKeyValueChangeNewKey]];
}
/*
如果父类实现了此方法,不要忘记调用。
NSObject 没有实现此方法.
*/
[super observeva lueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
删除观察者
?
?
- (void)unregisterForChangeNotification {
[observedObject removeObserver:inspector forKeyPath:@openingBalance];
}
?
四,遵循KVO
类的属性必须是遵循KVC的。使用KVC的方法修改了属性并触发通知。观察者注册了自身并实现了观察者方法。
有两种方式实现KVO,一种是自动通知方式,由NSObject支持,对所有遵循KVC的类的属性有效。一种是手动实现的,手动实现意味着更多的可控性,但也意味着更多的编码。
1,自动通知
例如demo工程KVOSalary
你可以发出自动通知通过以下几个方式:遵循KVC的setter方法,KVC方法,集合代理。
?
使用setter方法
[account setName:@Savings];
// 使用 setValue:forKey:.
[account setValue:@Savings forKey:@name];
// 使用keypath, where 'account' is a kvc-compliant property of 'document'.
[document setValue:@Savings forKeyPath:@account.name];
// 使用 mutableArrayValueForKey:返回集合代理.
Transaction *newTransaction = [[Transaction alloc]init];
NSMutableArray *transactions = [accoun