KVC基本概念:
a.kvc又称键值编码,是一种用于间接访问对象属性的机制,使用此机制不需要调用对象的存取(get和set)方法,也不用调用实例变量就能访问对象的属性,即使对象的属性为私有变量,kvc也能对此变量进行存取操作;
b.kvc的方法(-setValue: forKey: 和 -valueForKey:)有NSObject的非正式协议(类别)NSKeyValueCoding中被申明;
KVC的基本用法:
1.设置和访问:
kvc中的基本调用方法包括-setValue: forKey: 和 -valueForKey:这两个方法,他们以字符串形式向对象发送消息;
例:
Book *book = [[Book alloc] init]; [book setValue:@"ios编程思想" forKey:@"bookName"]; NSLog(@"book:%@",[book valueForKey:@"bookName"]);是否存在setter getter方法,如果不存在,将在内部查找名称为_key 或 key的实例变量,通过kvc,可以获取不存在getter方法的对象值,无需通过对象的指针访问。
需要注意的是,当我们通过setValue: forKey:设置对象的值或通过valueForKey:获取对象的值时,如果对象的实力变量为基本类型(char ,int ,float,bool),我们需要对数据进行封装
2.路径:方法(-setValue: forKeyPath: 和 -valueForKeyPath:)
除了通过key设置value外,kvc还支持路径,象文件路径一样,路径之间用" . "号隔开;
例:书对象中有个作者对象,作者对象中有name属性,通过book设置和获取到作者的name
Book *book = [[Book alloc] init]; [book setValue:@"wxxu" forKeyPath:@"author.name"]; [book valueForKeyPath:@"author.name"];
3.一对多的关系:
如果向一个NSArray数组中请求一个键值,它会查询数组中所有的对象来查找这个键值,然后将查询的结果打包到另一个数组中返回;
例:假设book中有个NSArray数组 相关书籍(relativeBooks)属性,现在想获取所有相关书籍的名称(reBookName)(只是讲解问题,不考虑实际意义)
Book *book = [[Book alloc] init];
NSArray *reBooks = [NSArray arrayWithObjects:reBook1,reBook2,reBook3,nil];
[book setValue:reBooks forKey:@"relativeBooks"];
NSArray *bookNames = [book valueForKeyPath:@"relativeBooks.reBookName"];//获取到所有的相关书籍对象的reBookName
4.KVC的简单运算:
kvc还可以做一些简单的运算,如:求和(sum),最大值最小值(max min),平均值(avg),个数(count)
用法:在以上关键字前加上@符号即可,然后加在你所求的属性前
例:求上面所有相关书籍的个数,总价格,最高价,最低价,平均价
Book *book = [[Book alloc] init]; [book valueForKeyPath:@"relativeBooks.@count"];//个数 [book valueForKeyPath:@"[email protected]"];//在price前加上@max求relativaBooks中price最大值,并返回最大值 [book valueForKeyPath:@"[email protected]"];//最小值 [book valueForKeyPath:@"[email protected]"];//平均值 [book valueForKeyPath:@"[email protected]"];//求和
KVO的基本概念:kvo使用了观察者模式,当被观察对象的属性发生变化时会通知观察者;
使用:kvo的使用简单的分为三步
1.注册观察者 2.实现回调方法(当被观察的属性发生变化时会回调此方法)3.移除观察者
实例:现在我们要观察Book对象的name属性(以下为伪代码,只为讲解知识点)
1.创建一个Book对象 @interface Book : NSObject{ NSString * name; int price; } @end 2.假设现在要在一个Controller中观察Book对象中的name属性 注册观察者:你要观察哪个对象中的属性就用哪个对象注册观察者(如下面方法要观察Book中的name就用book调用addObserver方法),observer:参数是你在什么对象中实现回调,此处我们在self中实现回调,forKeyPath中是要观察的属性名称(如观察name属性就填入name,此处支持kvc中提到的路径),options中填的是你想把name的旧值传到回调方法中,还是传新值,或新旧值都传 Book *book = [[Book alloc] init]; [book addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL]; 3.实现回调 方法的object参数就是观察的对象,此处是Book对象 ;change中能拿到修改前后的新旧数据(这要看注册观察者时传的是新值还是旧值,还是新旧都传) -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if([keyPath isEqualToString:@"name"]) //判断被观察的属性 { myLabel.text = [stockForKVO valueForKey:@"price"]; } } 4.取消观察 [book removeObserver:self forKeyPath:@"name"];
注意:如果需要实现kvo,必须调用kvc的setValueForKey方法,或对象属性的set方法(如book.name = @"aaaa")来改变被观察对象的属性,才能触发kvo的回调方法
如果在Book对象直接修改(如name=@"changeName"),没有调用其set方法是不会触发kvo回调的
备注:以上为本人浅见,如有不对,希望各位大大们指出纠正,谢谢!!