iOS KVC 键值编码

摘要:
1什么是键值编码?键值编码(Keyvalue coding,简称KVCKVC)通过字符串@Min间接获取和更改对象的状态。@Min类似于@sum,但最大值是计算出来的。

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;
}

免责声明:文章转载自《iOS KVC 键值编码》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇网站安全统一监测平台(WebPecker)eclipse项目出现红色叉叉解决方案下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

分析nginx日志常用的命令总结

1. 利用grep ,wc命令统计某个请求或字符串出现的次数 比如统计GET /app/kevinContent接口在某天的调用次数,则可以使用如下命令: cat /usr/local/nginx/logs/access.log | grep 'GET /app/kevinContent' | wc -l 其中cat用来读取日志内容,grep进行匹配的文...

iOS使用Charles 抓包并篡改返回数据图文详解

1.开始之前的准备工作 首先安装一下这个软件 这个相信很多人电脑里应该都安装了,没安装的搜charles破解版也能很容易搜到。如果没安装java环境,首次进入charles会提示让你安装java包得,直接给你链接是苹果官网的,去下一个一键安装就行了。  安装完成后先打开,在进行下面操作。 然后去自己电脑的系统偏好设置-》网络-》选中现在连着的网(大部分人应...

CoreLocation+MapKit系统定位(含坐标以及详细地址)

iOS8 之后出现一些新的配置 [self.manager requestWhenInUseAuthorization]; 并且在info.plist文件中增加 NSLocationWhenInUseUsageDescription BOOL YES NSLocationAlwaysUsageDescription string “...

Resource接口,及资源

Resource介绍 编码的时候,除了代码本身,我们还需要对外部的资源进行处理。例如:URL资源、URI资源、File资源、ClassPath相关资源、服务器相关资源(VFS等)等等。 而这些资源的处理是类似而繁琐的,如:打开资源、读取资源、关闭资源。 所以Spring提供了一个专门的接口Resource 用于统一这些底层资源的访问。 就是说,Spring...

豆瓣客户端(二)获取用户信息和搜索用户

之前写了豆瓣客户端(一)获取授权码和访问令牌后,就开始学习iOS7 TextKit方面的内容了,在前两天看Text Kit 看得无聊以后,又再回来写自己一直都很感兴趣的豆瓣客户端。途中遇到了各种各样的问题,先来小小吐槽一下:豆瓣的开发文档真是坑爹极了,基本上没有步骤可言,有时候就是一句带过,来个只能意会不能言传,难怪那么少人做豆瓣客户端,可能这个客户端赚不...

Yii2通过curl调用json-rpc接口

Yii2可以通过json-rpc为前端提供接口数据,通常情况睛会使用异步的形式调用接口,有时也会使用curl调用接口数据。 一、异步调用json-rpc接口 $.ajax({ type: 'POST', url: "http://localhost/index?r=test",...