您的位置:首页 > 移动开发 > IOS开发

iOS KVC 键值编码

2016-04-07 09:14 393 查看
1 什么是键值编码

键值编码,key value coding, 简称KVC

KVC, 通过字符串间接的获取、改变对象的状态。

2 KVC的基本使用

通过字符串获取对象的状态

接口oc对象的实例方法:- (id)valueForKey:(NSString *)key;
实例找name属性或者name方法 如果找不到,就找name和_name实例变量NSString *name = [car valueForKey:@”name”];
通过字符串设置对象的状态

接口oc对象的实例方法:- (void)setValue:(id)value forKey:(NSString *)key;
实例找name属性或者setName方法 如果找不到,就找name和_name实例变量 [car setValue:@”北京” forKey:@”name”];
car.h

struct size {
float length, width, height;
};

@interface Car : NSObject
{
NSString *serial;  //出厂编号
}

@property (nonatomic, copy) NSString *name; //品牌
@property (nonatomic) int years;
@property (nonatomic) CGRect rect;
@property (nonatomic, readonly) struct size  size;

@end


car.m

@implementation Car

- (instancetype) init
{
self = [super init];
if (self) {
_name = @"BYD";
_years = 3;
serial = @"12346789";
_rect = CGRectMake(10, 20, 30, 40);

_size.length = 5.0;
_size.width = 1.8;
_size.height = 1.7;
}
return self;
}

@end


main.m

int main(int argc, const char * argv[]) {
@autoreleasepool {
Car *car = [[Car alloc] init];

//找name属性或者name方法
NSString *name = [car valueForKey:@"name"];
NSLog(@"%@", name);

//找serial属性和serial方法都找不到
//就找serial和_serail实例变量
NSString *serial = [car valueForKey:@"serial"];
NSLog(@"%@", serial);

//valueForKey读取的值如果是标量类型(比如int,float等),则会自动装箱,返回NSNumber类型
NSNumber *years = [car valueForKey:@"years"];
NSLog(@"%d", [years intValue]);

//valueForKey读取的值如果是结构体类型, 则会自动装箱成NSValue类型
//常用结构体类型,可以使用对应的方法直接拆箱,比如rectValue
NSValue *rect = [car valueForKey:@"rect"];
CGRect rect2 = [rect rectValue];
NSLog(@"%.2f, %.2f, %.2f, %.2f",
rect2.origin.x, rect2.origin.y, rect2.size.width, rect2.size.height);

//valueForKey读取的值如果是结构体类型, 则会自动装箱成NSValue类型
//自定义的结构体类型,可以使用通用的getValue:方法拆箱
NSValue *size = [car  valueForKey:@"size"];
struct size size2;
[size getValue:&size2];
NSLog(@"%.2f, %.2f, %.2f", size2.length, size2.width, size2.height);

//设置
[car setValue:@"北京" forKey:@"name"];
NSLog(@"%@", car.name);

//设置标量值时,参数需要自己装箱
//在setValue:forKey:方法内部,会自动把表示值的参数进行拆箱
[car setValue:[NSNumber numberWithInt:4] forKey:@"years"];
NSLog(@"%d", car.years);
}
return 0;
}


3 键路径

接口-(id)valueForKeyPath:(NSString *)keyPath;
实例NSString *engineName = [car valueForKeyPath:@”engine.name”];
4 整体操作

键路径中,如果某个属性是一个集合类型(比如,数组、字典),则路径其后的部分将分别作用于该集合中的每一个对象。

接口1)valueForKeyPath: 对集合中的每个成员发送getter消息,并返回一个数组 2)setValue: forKeyPath:对集合中的每个成员发送setter消息
实例NSArray *pressures = [car valueForKeyPath:@”tires.pressure”];[car setValue:@15 forKeyPath:@”tires.pressure”];
5 使用KVC实现快速运算

@count

对@count左侧的的值统计总数, 返回NSNumber类型

接口在valueForKeyPath:中的键路径中使用@count
实例NSNumber *number = [car valueForKeyPath:@”tires.@count”];NSLog(@”tire count = %d”, [number intValue]);
@sum

接口在valueForKeyPath:中的键路径中使用@sum
实例NSNumber *pressureSum = [car valueForKeyPath:@”tires.@sum.pressure”]; NSLog(@”pressureSum = %2.f”, [pressureSum floatValue]);
@avg

与 @sum类似,但是计算的是平均值

接口在valueForKeyPath:中的键路径中使用@avg
实例NSNumber *pressureAvg = [car valueForKeyPath:@”tires.@avg.pressure”];NSLog(@”tire pressureAvg = %2.f”, [pressureAvg floatValue]);
@max

与 @sum类似,但是计算的是最大值。

@min

与 @sum类似,但是计算的是最大值。

@distinctUnionOfObjects

返回一个数组,重复值只取一个。

接口在valueForKeyPath:中的键路径中使用@ distinctUnionOfObjects
实例NSArray *array2 = [car valueForKeyPath:@”tires.@distinctUnionOfObjects.name”];NSLog(@”%@”, array2); //{3M}
6 使用KVC实现批处理

批处理获取多个属性的值,返回一个字典

接口(NSDictionary )dictionaryWithValuesForKeys:(NSArray )keys;
实例NSArray *keys = @[@”name”, @”years”];NSDictionary *values = [car dictionaryWithValuesForKeys:keys];NSLog(@”%@”, values);
批处理设置多个属性的值.

接口(void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
实例NSDictionary *dict = @{@”name”:@”BMW”, @”years”:@”5”};[car setValuesForKeysWithDictionary:dict];NSLog(@”%@, %d”, car.name, car.years);
7 处理未定义的键

使用KVC时,如果指定的键或键路径,没有直到对应的属性、方法或实例变量,则会抛出异常而终止。

解决方案:

使用valueForUndefinedKey:和setValue:forUndefinedKey:

对所有未定义的键做统一处理。

原理:

添加一个可变字典实例变量,

当遇到未定义的键时,将会调用对象的valueForUndefinedKey:方法,

在该方法内,把用户设置的未定义的键、值都保存到这个字典中。

这样就可以对该对象使用任意的键了。

demo

car.h

@interface Car : NSObject
{
NSMutableDictionary *_stuff;
}
@end


car.m

- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
//对_stuff实现惰性初始化,因为一般情况下不会使用未定义的键
if (_stuff == nil) {
_stuff = [[NSMutableDictionary alloc] init];
}
_stuff[key] = value;
}

- (id)valueForUndefinedKey:(NSString*)key
{
return _stuff[key];
}


main.m

int main(int argc, const char * argv[]) {
@autoreleasepool {
Car *car = [[Car alloc] init];

//直接使用未定义的键
[car setValue:@2700 forKey:@"weight"];
NSNumber *weight = [car valueForKey:@"weight"];
NSLog(@"%d kg", [weight intValue]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: