KVC/KVO之暴力的KVC

本章将分为三个部分:

  • KVC是什么
  • KVC之Set/Get
  • KVC键值路径之Set/Get

KVC是什么

KVC,即 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性,并不需要调用setter/getter函数或者类的实例变量。

 

KVC之Set/Get

类A中有3个变量,都是private权限,关于访问权限的,请参见《Objective-C 成员变量

A.h

@interface A : NSObject
{
@private
    NSString *str;
    NSInteger value;  //注意这里没星号哦哦哦
    NSArray *array;
}
@end

 

A.m:重写Description函数,用于NSLog

@implementation A
/**
 *    重写Description方法,可用于NSLog打印
 */
- (NSString *)description
{
    return [NSString stringWithFormat:@"\n%@\n%li\n%@", str, (long)value, array];
}
@end

 

Main.m:理论上来说,外部变量是访问不到这3个私有变量的,但是暴力的KVC来了。

A *a = [[A alloc] init];

//KVC之set
[a setValue:@"HelloWorld" forKey:@"str"];
[a setValue:@2015 forKey:@"value"];
[a setValue:@[@"HearthStone", @2] forKey:@"array"];

NSLog(@"%@", a);

//KVC之get
NSString *str = [a valueForKey:@"str"];
NSInteger value = [[a valueForKey:@"value"] integerValue];  //id 转为 NSInteger
NSArray *array = [a valueForKey:@"array"];

NSLog(@"\n%@\n%ld\n%@", str, (long)value, array);

 

输出为

HelloWorld
2015
(
HearthStone,
2
)

HelloWorld
2015
(
HearthStone,
2
)

 

分析:

KVC的Set方法(重点)

[a setValue:@"HelloWorld" forKey:@"str"];

是KVC的set方法,其中key一定要为消息接收者的属性名称,而不能是自定义的。

 

KVC的Get方法(重点)

NSString *str = [a valueForKey:@"str"];

是KVC的get方法,其中key一定要为消息接收者的属性名称,而不能是自定义的。

 

当Set方法遇到基本数据类型

[a setValue:@2015 forKey:@"value"];

NSInteger是基本数据类型,设置基本数据类型的时候,需要将基本类型转化成NSNumber,在设置值的时候,系统会有自动解包的过程,NSNumber会解包赋值给value.

 

当Get方法遇到基本数据类型

NSInteger value = [[a valueForKey:@"value"] integerValue];  //id 转为 NSInteger

valueForKey返回的是id类型,id转换为NSInteger的方法应该是上面这种,而下面这种写法是错误的!

NSInteger value = (NSInteger)[a valueForKey:@"value"];

 

题外话:重写Description来方便NSLog的输出

- (NSString *)description
{
    return [NSString stringWithFormat:@"\n%@\n%li\n%@", str, (long)value, array];
}

NSLog(@"%@", a);

将打印出

HelloWorld
2015
(
HearthStone,
2
)

 

KVC键值路径之Set/Get

假如A含有一个类B,那么如何通过KVC拿到B的属性呢?答案是使用键值路径。

A.h

@interface A : NSObject
{
@private
    NSString *str;
    NSInteger value;  //注意这里没星号哦哦哦
    NSArray *array;
    B *b;
}
@end

 

B.h

@interface B : NSObject
{
@private
    NSinteger *age;
}
@end

 

现在,假如A的array里面装的都是B(装B--)

Main.m

A *a = [[A alloc] init];
...//set Object
[a setValue:@23 forKeyPath:@"b.age"];

NSArray *array = [a valueForKeyPath:@"array.age"];        //返回了数组中所有B的age
NSInteger count = [a valueForKeyPath:@"array.@count"];    //返回了数组中B的个数
NSInteger maxAge = [a valueForKeyPath:@"array.@max.age"]; //返回了数组中B的age最大的
NSInteger sumAge = [a valueForKeyPath:@"array.@sum.age"]; //返回了数组中B的age和
NSInteger avgAge = [a valueForKeyPath:@"array.@avg.age"]; //返回了数组中B的age平均值

 

键值路径可以用来访问不是基本类型的实例变量的属性,也可以快速取到数组中的对象的同一个属性,同时可以利用@count @max @sum @avg等进行计算。

KVC的键值路径的Set方法(重点)

[a setValue:@23 forKeyPath:@"b.age"];

 

KVC的键值路径的Get方法(重点)

NSArray *array = [a valueForKeyPath:@"array.age"];        //返回了数组中所有B的age

 

posted @ 2015-09-12 22:50  Norcy  阅读(320)  评论(0编辑  收藏  举报