目录

什么是KVC?

为什么要用KVC?

KVC用法介绍.

什么是KVC?

KVC是cocoa的一部分,可以使我们在访问对象属性的时候不需要再调用 setter 和 getter存取器,比如我们可以用 [object valueForKey:property]来访问object对象中的property属性,也能用 [object setValue:value forKey:property]来给object对象中的property属性赋值。为了达到这种目的,对象需要用特定的方式来命名方法,这种命名约定就成为KVC.

为什么要用KVC

使用KVC能让我们在运行时而非编译时决定访问哪个属性,从而得到更灵活和更易于重用的对象,同时也能帮助我们减少代码量,通过KVC,还能实现cocoa中更为强大的KVO功能。

KVC用法介绍

我们定义一个对象如下

@interface People : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *age;
@property (nonatomic, strong) Car *car;
@end

访问对象属性

我们在获取people对象的name属性的值的时候,就可以通过KVC来获取:

 NSString *name = [people valueForKey:@"name"];

此代码基本等同于下面代码

NSString *name = people.name;

用KVC赋值

KVC可以用setValue:forKey:修改可写属性:

[people setValue:@"Alex" forKey:@"name"];

此代码基本等同与下面代码

people.name = @"Alex";

keyPath

KVC 方法有 key 和keyPath 两个版本,比如 valueForkey: 和 valueForKeyPath:版本,这两者的区别在于,后者可以包含嵌套关系,用点分开,valueForKeyPath方法可以遍历所有的关系,如下所示:

	NSString *carName = [people valueForKayPath:@"car.name"];

此方法用来获取people对象的车的名称,可以基本等价于下面代码:

	NSString *carName = [[people car] name];

而 key方法不会遍历关系,假如你使用

	NSString *carName = [people valueForKay:@"car.name"];

程序会去获取 people对象 的 car.name 属性,很明显,people 没有这样的属性,所以系统会抛出异常。

KVC和非对象

KVC 的 valueForKey:方法总是返回一个id对象,但不是每一个方法都会返回对象,那么对于标量,该方法返回值会自动用NSValue 或 NSNumber 来进行封装。因此我们在通过 KVC 赋值的对象为标量的时候,也应该先用 NSValue 或 NSNumber 进行封装,然后再使用 setValue:forKey:方法。

高阶消息传递

valueForKey:有很多有用的特例,比如对于 NSArray 或 NSSet 等容器类,使用 valueForKey:方法,实际上该方法会被传递给容器中的每一个对象,而不是对容器本身进行操作,它会对容器中的每个对象来查找这个键值,然后将查询结果打包到另一个容器中并返回给你。这样,我们就很容易用一个容器对象创建另一个容器对象。

比如:

People *developer = [[People alloc] init];
[developer setValue:@"Alex" forKey:@"name"];

People *teacher = [[People alloc] init];
[teacher setValue:@"Lucy" forKey:@"name"];

NSArray *array = @[developer,teacher];

NSArray *nameArray = [array valueForKey:@"name"];

name 被传递给array中的每一个元素,并返回一个新的数组,新的数组中的元素是一个姓名的字符串。 对于 keyPath 使用方法也类似:

	NSArray *nameLengthArray = [array valueForKeyPath:@"name.length"];

新的数组中的元素是用 NSNumber 封装的姓名字符串的长度。

####通过KVC创建Model

我们经常会遇到需要将一个字典转化成一个对象情况,这时用 KVC 能很好的解决问题, KVC 中有一个setValuesForKeysWithDictionary: 方法,此方法能很好的把字典转换成我们需要的对象。比如我们可以给刚才的 People 类增加一个初始化方法:

-(id) initWithDictionary:(NSMutableDictionary*) jsonObject;

实现如下:

-(id) initWithDictionary:(NSMutableDictionary*) jsonObject
{
    if((self = [super init]))
    {
        [self setValuesForKeysWithDictionary:jsonObject];
    }
    return self;
}

一些特殊的用法

KVC还提供一些特殊的方法,例如获取一组值的平均值或返回这组值的最小值和最大值。例如:

NSArray *array = @[developer,teacher];
NSNumber *totalLength = [array valueForKeyPath:@"name.@sum.length"]; 	

@sum是一个操作符,对指定的属性(name.length)求和。