KVC 与 KVO 是 Objective C 的关键概念,是必须要理解的东西
下面是实例讲解。
一、KVC – Key-Value Coding
KVC,即是指NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性。KVO 就是基于 KVC 实现的关键技术之一。
一个对象拥有某些属性。比如说,一个 Person 对象有一个 name 和一个 address 属性。以 KVC 说法,Person 对象分别有一个 value 对应他的 name 和 address 的 key。 key 只是一个字符串,它对应的值可以是任意类型的对象。从最基础的层次上看,KVC 有两个方法:
一个是设置 key 的值,
另一个是获取 key 的值。
如下面的例子:
// Person.h#import //@interfacePerson:NSObject
//@property(nonatomic,strong)NSString*name;
@property(nonatomic,strong)NSString*address;
@property(nonatomic,strong)Person*spouse;//@end
// ViewController.m
-(void)viewDidLoad{[superviewDidLoad];
//Person*person=[[Personalloc]init];person.name=@"Jack";person.address=@"chengdu";
//[selfchangePerson:personName:@"Kevin"];
}
//-(void)changePerson:(Person*)personName:(NSString*)newName{
// using the KVC accessor (getter) methodNSString*originalName=[personvalueForKey:@"name"];
//// using the KVC accessor (setter) method.[personsetValue:newNameforKey:@"name"];
//NSLog(@"changed %@`s name to: %@",originalName,person.name);//输出:changed Jack`s name to: Kevin
}
现在,如果 Person 有另外一个 key 配偶(spouse),spouse 的 key 值是另一个 Person 对象,用 KVC 可以这样写:
-(void)viewDidLoad{
[superviewDidLoad];
//Person*person=[[Personalloc]init];
person.name=@"Jack";
person.address=@"chengdu";
//[selfchangePerson:personName:@"Kevin"];
//Person*spouse=[[Personalloc]init];spouse.name=@"Rose";spouse.address=@"chengdu";
//person.spouse=spouse;
//[selflogMarriage:person];}
//-(void)logMarriage:(Person*)person{
// just using the accessor again, same as example above
NSString*personName=[personvalueForKey:@"name"];
//// this line is different, because it is using
// a "key path" instead of a normal "key"
NSString*spouseName=[personvalueForKeyPath:@"spouse.name"];
//NSLog(@"%@ is happliy married to %@",personName,spouseName);//}
key与key path要区分开来,key可以从一个对象中获取值,而key path可以将多个 key 用点号 “.” 分割连接起来,比如上面例子中的:
[pvalueForKeyPath:@"spouse.name"];
相当于这样……
[[pvalueForKey:@"spouse"]valueForKey:@"name"];
好了,以上是 KVC 的基本知识,接着看看 KVO。
二、KVO – Key-Value Observing
Key-Value Observing (KVO)建立在 KVC 之上,它能够观察一个对象的 KVC key path 值的变化。举个例子,用代码观察一个 person 对象的 address 变化,以下是实现的三个方法:
watchPersonForChangeOfAddress:实现观察
observeValueForKeyPath:ofObject:change:context:在被观察的 key path 的值变化时调用。
dealloc停止观察
举个例子如下:
staticNSString*constKVO_CONTEXT_ADDRESS_CHANGED=@"KVO_CONTEXT_ADDRESS_CHANGED";
//@implementationViewController
//-(void)watchPersonForChangeOfAddress:(Person*)person{
// this begins the observing[personaddObserver:selfforKeyPath:@"address"options:0context:(__bridgevoid*_Nullable)(KVO_CONTEXT_ADDRESS_CHANGED)];
//// keep a record of all the people being observed,
// because we need to stop observing them in dealloc[m_observedPeopleaddObject:person];
}
//-(void)observeValueForKeyPath:(NSString*)keyPathofObject:(id)objectchange:(NSDictionary*)changecontext:(void*)context{
//if(context==(__bridgevoid*_Nullable)(KVO_CONTEXT_ADDRESS_CHANGED)){NSString*name=[objectvalueForKey:@"name"];
NSString*address=[objectvalueForKey:@"address"];
NSLog(@"%@ has a new address: %@",name,address);}}
//-(void)dealloc{
//// must stop observing everything before this object is
// deallocated, otherwise it will cause crashes
for(Person*personinm_observedPeople){
[personremoveObserver:selfforKeyPath:@"address"];}m_observedPeople=nil;
}
@end
在这个例子中,当 person 的 aaddress 一旦发生改变,就会NSLog(@"%@ has a new address: %@", name, address);,这就是 KVO 的作用,它通过key path观察对象的值,当值发生变化的时候会收到通知。