kvc:键 – 值编码是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取方法,直接或通过实例变量访问的机制。
很多情况下可以简化程序代码。apple文档其实给了一个很好的例子。
kvo:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。
具体用看到嗯哼用到过的一个地方是对于按钮点击变化状态的的监控。
比如我自定义的一个button
[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil];
#pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"highlighted"] ) {
[self setNeedsDisplay];
}
}
对于系统是根据keypath去取的到相应的值发生改变,理论上来说是和kvc机制的道理是一样的。
对于kvc机制如何通过key寻找到value:
“当通过KVC调用对象时,比如:[self valueForKey:@”someKey”]时,程序会自动试图通过几种不同的方式解析这个调用。首先查找对象是否带有 someKey 这个方法,如果没找到,会继续查找对象是否带有someKey这个实例变量(iVar),如果还没有找到,程序会继续试图调用 -(id) valueForUndefinedKey:这个方法。如果这个方法还是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误。
(cocoachina.com注:Key-Value Coding查找方法的时候,不仅仅会查找someKey这个方法,还会查找getsomeKey这个方法,前面加一个get,或者_someKey以及_getsomeKey这几种形式。同时,查找实例变量的时候也会不仅仅查找someKey这个变量,也会查找_someKey这个变量是否存在。)
设计valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey方法从对象中请求值时,对象能够在错误发生前,有最后的机会响应这个请求。这样做有很多好处,下面的两个例子说明了这样做的好处。“
来至cocoa,这个说法应该挺有道理。
因为我们知道button却是存在一个highlighted实例变量.因此为何上面我们只是add一个相关的keypath就行了,
可以按照kvc查找的逻辑理解,就说的过去了。
#import "ViewController.h"
#import "Car.h"
@interfaceViewController ()
{
Car *newCar;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//演示KVC,KVO的使用
//<1>KVC使用
// 什么是KVC
// 是啥: Key Value Coding 键值编码
// 干嘛: 以字符串作为key, 访问对象属性的一种方式
[selftestKVC];
//<2>KVO的使用
//key value observing 键值监听
//实时监控, 车速一旦变化, 立马显示
[selftestKVO];
}
-(void)testKVO
{
//2.什么是kvo
//key value observing 键值监听
//实例: 汽车显示频显示当前车的速度
newCar = [[Caralloc] init];
//实时监控, 车速一旦变化, 立马显示
//作用: 当newCar中speed属性变化的时候, 执行self中指定方法
[newCaraddObserver:selfforKeyPath:@"speed"options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNewcontext:nil];
newCar.speed = 0;
newCar.speed = 10;
newCar.speed = 60;
newCar.speed = 120;
newCar.speed = 120;
}
-(void)dealloc
{
[newCarremoveObserver:selfforKeyPath:@"speed"];
}
//参数1: 表示那个属性改变了
//参数2: 那个对象的属性改变了
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
double speed = [[object valueForKeyPath:keyPath] doubleValue];
NSLog(@"speed = %f",speed);
}
-(void)testKVC
{
//1. KVC
// 什么是KVC
// 是啥: Key Value Coding 键值编码
// 干嘛: 以字符串作为key, 访问对象属性的一种方式
// kVC的作用
Car *car = [[Caralloc] init];
car.type = @"BMW";
car.speed = 200;
NSLog(@"type = %@, speed=%f",car.type,car.speed);
[car setValue:@"奇瑞QQ"forKey:@"type"];
[car setValue:@(120)forKey:@"speed"];
NSLog(@"t = %@,s = %f",[car valueForKey:@"type"],
[[car valueForKey:@"speed"] doubleValue]);
// 解析中可能出现的问题
[car setValue:@"奇瑞QQ"forKey:@"unknown"];
// keyPath的使用 - 处理多层嵌套的属性
Engine *e = [[Enginealloc] init];
e.power = 1000000;
car.engine = e;
//修改power
[car setValue:@(2000000)forKeyPath:@"engine.power"];
NSLog(@"p = %f",[[car valueForKeyPath:@"engine.power"] doubleValue]);
// 字典转化为对象
NSDictionary *dict = @{@"type":@"dongfeng",@"speed":@(20000)};
Car *newCar = [[Caralloc] init];
[newCar setValuesForKeysWithDictionary:dict];
NSLog(@"%@ %f",newCar.type,newCar.speed);
// KVC的原理
[car mySetValue:@"mini"forKey:@"type"];
NSLog(@"t = %@",car.type);
NSLog(@"t = %@",[car myValueForKey:@"type"]);
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end