KVC(Key-Value Coding)是一种机制,通过该机制可以使用字符串来访问对象的属性和成员变量。iOS开发中,KVC是一个很常用的技术,在实际开发中也有很多应用场景。
KVC的原理
KVC的原理很简单,就是利用字符串来动态地访问一个对象的属性和成员变量。在Objective-C中,每个类都有一个方法叫做setValue:forKey:,这个方法可以接收一个任意类型的对象和一个字符串作为参数。当我们调用这个方法时,系统会根据传入的字符串来查找对象的属性或成员变量,并将传入的值设置给它。
举个例子,如果我们有一个Person类,其中包含一个名为name的成员变量,那么我们可以通过以下代码来设置它的值:
1
2
Person *p = [[Person alloc] init];
[p setValue:@"张三" forKey:@"name"];
KVC的优势
使用KVC的好处主要有以下几点:
- 动态访问属性或成员变量
使用KVC可以动态地访问一个对象的属性或成员变量,不需要在代码中直接写出属性或成员变量的名称,从而提高了代码的灵活性和可维护性。
- 对象与字典之间的转换
在实际开发中,我们经常需要将一个对象转换为字典,或者将一个字典转换为对象。这时候,使用KVC可以非常方便地实现这个功能。我们可以利用setValue:forKey:方法将一个对象的属性值设置为字典中对应的值,也可以利用valueForKey:方法将一个字典中的值取出来并赋给对象的属性。
- 远程配置
有些应用程序需要在运行时从服务器获取配置信息,此时我们可以使用KVC来完成这个功能。例如,我们可以将服务器返回的JSON数据解析成字典,然后通过KVC将字典中的值设置为对象的属性。
KVC的使用
设置属性值
使用KVC设置属性值非常简单,只需要调用对象的setValue:forKey:方法,传入要设置的值和属性名称即可。例如:
1
2
Person *p = [[Person alloc] init];
[p setValue:@"张三" forKey:@"name"];
注意,被设置的属性必须是可写的,否则会导致运行时错误。
获取属性值
使用KVC获取属性值也非常简单,只需要调用对象的valueForKey:方法,传入属性名称即可。例如:
1
NSString *name = [p valueForKey:@"name"];
同样地,被获取的属性必须是可读的,否则会导致运行时错误。
访问私有成员变量
有些情况下,我们需要访问对象的私有成员变量,而这些成员变量通常是不可访问的。使用KVC可以轻松地实现这个功能,只需要将成员变量的名称以“_”开头即可。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//KVC实现
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *publicProperty;
@end
@implementation MyClass {
NSString *_privateProperty;
}
- (instancetype)init {
if (self = [super init]) {
_privateProperty = @"privateValue";
}
return self;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 创建对象
MyClass *obj = [[MyClass alloc] init];
// 访问私有成员变量
[obj setValue:@"newValue" forKey:@"_privateProperty"];
NSLog(@"%@", [obj valueForKey:@"_privateProperty"]);
}
return 0;
}
//runtime实现
Ivar ivar = class_getInstanceVariable([self class\], "_privateProperty");
id value = object_getIvar(self, ivar);
字典转模型
在实际开发中,我们经常需要将服务器返回的JSON数据解析成模型对象。这个过程可以通过KVC来实现,其步骤如下:
- 将JSON数据解析成字典;
- 创建模型对象;
- 遍历字典中的键值对,将值设置为模型对象的属性值。
代码示例:
1
2
3
4
5
6
7
NSDictionary *jsonData = ...; // 服务器返回的JSON数据
Person *p = [[Person alloc] init]; // 创建模型对象
for (NSString *key in jsonData) {
id value = [jsonData objectForKey:key];
[p setValue:value forKey:key];
}
注意,这个过程中,字典中的键值对必须与模型对象的属性名称一一对应。
模型转字典
有时候,我们需要将一个模型对象转换成字典,以便于上传到服务器或者存储到本地。这时候,我们可以利用KVC来实现这个功能。代码示例:
1
NSDictionary *dict = [p dictionaryWithValuesForKeys:@[@"name", @"age", @"gender"]];
这里使用了NSDictionary类的dictionaryWithValuesForKeys:方法,它会返回一个字典,该字典包含指定的键所对应的值。
应用举例
使用KVC验证表单:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (NSDictionary *)validateFormWithInputs:(NSArray<NSDictionary<NSString *, NSString *> *> *)inputs {
NSMutableDictionary *validatedInputs = [NSMutableDictionary dictionary];
for (NSDictionary<NSString *, NSString *> *input in inputs) {
NSString *propertyName = input.allKeys.firstObject;
NSString *propertyValue = input.allValues.firstObject;
if ([self valueForKey:propertyName] == nil || [propertyValue isEqualToString:@""]) {
return nil;
}
validatedInputs[propertyName] = propertyValue;
}
return validatedInputs;
}