KVC
KVC定义
KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。很多高级的iOS开发技巧都是基于KVC实现的。
一个对象拥有某些属性。比如说,一个 Person 对象有一个 name 和一个 address 属性。以 KVC 说法,Person 对象分别有一个 value 对应他的 name 和 address 的 key。 key 只是一个字符串,它对应的值可以是任意类型的对象。从最基础的层次上看,KVC 有两个方法:一个是设置 key 的值,另一个是获取 key 的值。如下面的例子:
void changeName(Person *p, NSString *newName)
{
// using the KVC accessor (getter) method
NSString *originalName = [p valueForKey:@"name"];
// using the KVC accessor (setter) method.
[p setValue:newName forKey:@"name"];
NSLog(@"Changed %@'s name to: %@", originalName, newName);
}
KVO
KVO全称KeyValueObserving,是苹果提供的一套事件通知机制。允许对象监听另一个对象特定属性的改变,并在改变时接收到事件。由于KVO的实现机制,所以对属性才会发生作用,一般继承自NSObject的对象都默认支持KVO。
Key-Value Observing (KVO) 建立在 KVC 之上,它能够观察一个对象的 KVC key path 值的变化。举个例子,用代码观察一个 person 对象的 address 变化,以下是实现的三个方法:
KVO和NSNotificationCenter都是iOS中观察者模式的一种实现。区别在于,相对于被观察者和观察者之间的关系,KVO是一对一的,而不一对多的。KVO对被监听对象无侵入性,不需要修改其内部代码即可实现监听。
KVO可以监听单个属性的变化,也可以监听集合对象的变化。通过KVC的mutableArrayValueForKey:等方法获得代理对象,当代理对象的内部对象发生改变时,会回调KVO监听的方法。集合对象包含NSArray和NSSet。
使用KVO分为三个步骤:
- 通过addObserver:forKeyPath:options:context:方法注册观察者,观察者可以接收keyPath属性的变化事件。
- 在观察者中实现observeValueForKeyPath:ofObject:change:context:方法,当keyPath属性发生改变后,KVO会回调这个方法来通知观察者。
- 当观察者不需要监听时,可以调用removeObserver:forKeyPath:方法将KVO移除。需要注意的是,调用removeObserver需要在观察者消失之前,否则会导致Crash。
代码如下所示
[param addObserver:self
forKeyPath:@"address"
options:0
context:KVO_CONTEXT_ADDRESS_CHANGED];
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{}
注册方法
在注册观察者时,可以传入options参数,参数是一个枚举类型。如果传入NSKeyValueObservingOptionNew和NSKeyValueObservingOptionOld表示接收新值和旧值,默认为只接收新值。如果想在注册观察者后,立即接收一次回调,则可以加入NSKeyValueObservingOptionInitial枚举。
还可以通过方法context传入任意类型的对象,在接收消息回调的代码中可以接收到这个对象,是KVO中的一种传值方式。
在调用addObserver方法后,KVO并不会对观察者进行强引用,所以需要注意观察者的生命周期,否则会导致观察者被释放带来的Crash。
监听方法
观察者需要实现observeValueForKeyPath:ofObject:change:context:方法,当KVO事件到来时会调用这个方法,如果没有实现会导致Crash。change字典中存放KVO属性相关的值,根据options时传入的枚举来返回。枚举会对应相应key来从字典中取出值,例如有NSKeyValueChangeOldKey字段,存储改变之前的旧值。
change中还有NSKeyValueChangeKindKey字段,和NSKeyValueChangeOldKey是平级的关系,来提供本次更改的信息,对应NSKeyValueChange枚举类型的value。例如被观察属性发生改变时,字段为NSKeyValueChangeSetting。
如果被观察对象是集合对象,在NSKeyValueChangeKindKey字段中会包含NSKeyValueChangeInsertion、NSKeyValueChangeRemoval、NSKeyValueChangeReplacement的信息,表示集合对象的操作方式。