iOS KVC 键值编码
2016-04-07 09:14
393 查看
1 什么是键值编码
键值编码,key value coding, 简称KVC
KVC, 通过字符串间接的获取、改变对象的状态。
2 KVC的基本使用
通过字符串获取对象的状态
通过字符串设置对象的状态
car.h
car.m
main.m
3 键路径
4 整体操作
键路径中,如果某个属性是一个集合类型(比如,数组、字典),则路径其后的部分将分别作用于该集合中的每一个对象。
5 使用KVC实现快速运算
@count
对@count左侧的的值统计总数, 返回NSNumber类型
@sum
@avg
与 @sum类似,但是计算的是平均值
@max
与 @sum类似,但是计算的是最大值。
@min
与 @sum类似,但是计算的是最大值。
@distinctUnionOfObjects
返回一个数组,重复值只取一个。
6 使用KVC实现批处理
批处理获取多个属性的值,返回一个字典
批处理设置多个属性的值.
7 处理未定义的键
使用KVC时,如果指定的键或键路径,没有直到对应的属性、方法或实例变量,则会抛出异常而终止。
解决方案:
使用valueForUndefinedKey:和setValue:forUndefinedKey:
对所有未定义的键做统一处理。
原理:
添加一个可变字典实例变量,
当遇到未定义的键时,将会调用对象的valueForUndefinedKey:方法,
在该方法内,把用户设置的未定义的键、值都保存到这个字典中。
这样就可以对该对象使用任意的键了。
demo
car.h
car.m
main.m
键值编码,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”]; |
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”]; |
键路径中,如果某个属性是一个集合类型(比如,数组、字典),则路径其后的部分将分别作用于该集合中的每一个对象。
接口 | 1)valueForKeyPath: 对集合中的每个成员发送getter消息,并返回一个数组 2)setValue: forKeyPath:对集合中的每个成员发送setter消息 |
---|---|
实例 | NSArray *pressures = [car valueForKeyPath:@”tires.pressure”];[car setValue:@15 forKeyPath:@”tires.pressure”]; |
@count
对@count左侧的的值统计总数, 返回NSNumber类型
接口 | 在valueForKeyPath:中的键路径中使用@count |
---|---|
实例 | NSNumber *number = [car valueForKeyPath:@”tires.@count”];NSLog(@”tire count = %d”, [number intValue]); |
接口 | 在valueForKeyPath:中的键路径中使用@sum |
---|---|
实例 | NSNumber *pressureSum = [car valueForKeyPath:@”tires.@sum.pressure”]; NSLog(@”pressureSum = %2.f”, [pressureSum floatValue]); |
与 @sum类似,但是计算的是平均值
接口 | 在valueForKeyPath:中的键路径中使用@avg |
---|---|
实例 | NSNumber *pressureAvg = [car valueForKeyPath:@”tires.@avg.pressure”];NSLog(@”tire pressureAvg = %2.f”, [pressureAvg floatValue]); |
与 @sum类似,但是计算的是最大值。
@min
与 @sum类似,但是计算的是最大值。
@distinctUnionOfObjects
返回一个数组,重复值只取一个。
接口 | 在valueForKeyPath:中的键路径中使用@ distinctUnionOfObjects |
---|---|
实例 | NSArray *array2 = [car valueForKeyPath:@”tires.@distinctUnionOfObjects.name”];NSLog(@”%@”, array2); //{3M} |
批处理获取多个属性的值,返回一个字典
接口 | (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); |
使用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; }
相关文章推荐
- iOS 存储数据
- 给NIOS II CPU添加一颗澎湃的心——sysclk的使用
- iOS 消息通讯
- 【代码笔记】iOS-将log日志保存到文件
- 【代码笔记】iOS-将log日志保存到文件
- iOS 微博 sdk access_token 过期重登
- iOS 微博 sdk 私信邀请全部好友
- iOS 微博 sdk 私信邀请指定好友
- IOS混合编程 - NSURLProtocol 的使用 (三)
- iOS 微博sdk分享(直接分享,跳过编辑页面)
- 关于iOS中AES加密和base64编码的理解
- iOS 微博 sdk 分享文字图片
- iOS 获取当前时间
- iOS:通知机制的详解与代码示例
- iOS 类方法与对象方法
- iOS学习资源(一)
- iOS @@创建NSURL的字面量
- iOS--浅谈iOS沙盒目录
- ios中的定时
- 第一个ios程序中的问题