结合之前的学习笔记以及参考《Objective-C编程全解(第三版)》,对Objective-C知识点进行梳理总结。知识点一直在变,只是作为参考,以苹果官方文档为准~
十七、键值编码 KVC
关于KVC的知识点将通过下列例子来展开说明:
Person.h文件,Person类拥有name和age两个成员变量
@interface Person : NSObject {
@private
NSString *_name;
NSInteger _age;
}
- (void)setAge:(NSInteger)age;
@end
Person.m实现了该方法
@implementation Person
- (NSString *)description {
return [NSString stringWithFormat:@"name:%@,age=%li", _name, _age];
}
- (void)setAge:(NSInteger)age {
_age = age;
}
@end
main.m
Person *p = [[Person alloc] init];
// p->_name = @"Zane"; 不可访问
//1.使用KVC给private的属性设置值
[p setValue:@"Zane" forKey:@"name"];
//2.通过KVC获取到属性值
NSString *name = [p valueForKey:@"_name"];
NSLog(@"%@", name);
[p setValue:@21 forKey:@"age"];
NSLog(@"%@", p);
output:
2015-07-09 17:29:43.477 exercise_KVC[579:24344] Zane
2015-07-09 17:29:43.478 exercise_KVC[579:24344] name:Zane,age=21
1、键值编码(key-value coding):将表示对象包含的信息的字符串作为键值使用,来间接访问该信息的方式。
基本上,只要存在访问器方法、声明属性或实例变量,就可以将其名字作为字符串访问。(即使这个变量时@private私有的,也能访问)
2、设置属性值:
- (void)setValue:(id)value forKey:(NSString *)key; //已进行内存管理
[p setValue:@"Zane" forKey:@"name"];
a、如果此处name写错了,写成nama,nam1e等等,编译器不会报错,但会导致运行崩溃
b、value为id类型,因此如果是基本数据类型需要进行包装
获取属性值
- (id)valueForKey:(NSString *)key;
NSString *name = [p valueForKey:@"_name"];
如果人还拥有一条狗,以@class的方式加在Person.h中,狗有dogName属性,那么可以指定路径设置
[p setValue:@"wangwang" forKeyPath:@"dog._dogname"];
NSLog(@"%@",[p valueForKeyPath:@"dog._dogname"])
- (id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
3、缺点
(1)破坏了面向对象的封装性;
(2)编译器不会对设置的keyValue进行错误检查;
(3)需要先对字符串进行解析,执行效率低于set和get方法
4、其他说明
(1)使用KVC设置属性,优先去当前类中查找是否有相应的set方法,如果有使用set方法设置,若无则找到属性设置
要调用只能写age不能写_age
例如例子中的
[p setValue:@21 forKey:@"age"];
[p setValue:@21 forKey:@"_age"];
可以在age的set方法实现处设置断点,会发现,如果写_age则不调用set方法
(2)一对多的关系
一般先打包成NSArray,再通过setValue方法,作为value赋值。
访问的时候通过路径访问valueForKeyPath访问
(3)数值计算
在上述例子中为Person增加book成员变量;
并且Dog.h拥有成员变量dogage
@interface Dog : NSObject
{
int _dogage;
}
- (instancetype)initWithAge:(int)age; //并实现
@end
main.m
Dog* dog1 = [[Dog alloc] initWithAge:20];
Dog* dog2 = [[Dog alloc] initWithAge:30];
Dog* dog3 = [[Dog alloc] initWithAge:10];
NSArray *array = [NSArray arrayWithObjects:dog1,dog2,dog3, nil];
[p setValue:array forKey:@"dog"]; //前面已定义
NSLog(@"%@",[p valueForKeyPath:@"dog.@count"]); //dog数量
NSLog(@"%@",[p valueForKeyPath:@"dog.@sum._dogage"]); //所有dogage总和
NSLog(@"%@",[p valueForKeyPath:@"dog.@avg._dogage"]); //平均值
NSLog(@"%@",[p valueForKeyPath:@"dog.@min._dogage"]); //最小值
NSLog(@"%@",[p valueForKeyPath:@"dog.@max._dogage"]); //最大值
output:
2015-07-09 17:29:43.479 exercise_KVC[579:24344] 3
2015-07-09 17:29:43.479 exercise_KVC[579:24344] 60
2015-07-09 17:29:43.480 exercise_KVC[579:24344] 20
2015-07-09 17:29:43.480 exercise_KVC[579:24344] 10
2015-07-09 17:29:43.480 exercise_KVC[579:24344] 30