简单使用
/// 创建学生对象
@interface DDStudent : NSObject
@property (nonatomic, strong) NSString *name;
@end
/// 创建人对象
@interface DDPerson : NSObject
@property (nonatomic, assign) int age;
/// 把学生对象设置为属性
@property (nonatomic, strong) DDStudent *student;
@end
/// 实现
int main(int argc, const char * argv[]) {
@autoreleasepool {
/// 创建实例
DDPerson *person = [[DDPerson alloc] init];
person.student = [[DDStudent alloc] init];
/// KVC设置属性的值
[person setValue:@10 forKey:@"age"];
/// 注意如果属性是复杂对象,就应该使用forKeyPath赋值
[person setValue:@"小明" forKeyPath:@"student.name"];
NSLog(@"age = %d, studentName = %@", person.age, person.student.name);
/// 结果:age = 10, studentName = 小明
}
return 0;
}
实现原理
赋值原理
KVC赋值调用setValue:forKey: 或者setValue:forKeyPath:具体流程是如何实现的
- 首先按照顺序查找setKey:和_setKey: 方法,如果查找到则传入参数,调用方法,如果没有找到走第二步
- 查看accessInstanceVariableDirectily方法返回值,如果返回NO,则报错NSUnknownKeyException,意思就是没有找到这个Key。如果上一步返回YES,走第三步
- 按顺序查找 _key、_isKey、key、_isKey 四个成员变量,如果找到了那么就直接赋值,如果没有则报错NSUnknownKeyException,意思就是没有找到这个Key
具体流程可看下图
上图就是KVC赋值的过程,通过上图我们可以很清楚的看到是如何赋值的
取值原理
调用valueForKey:
- 首先按循序查找getKey、key、isKey、_Key方法,如果查找到了则直接调用方法。如果没有查找到走第二步
- 跟赋值第二步一样
取值过程我们也可以看这张图
补充——KVC能触发KVO吗
如果一个属性添加了KVO,那么使用KVC是可以触发KVO。由于触发KVO的条件就是调用了Setter方法,而KVC内部实现的时候也是调用了setter方法的。还有一点就是在第一步就算没有找到setter方法,那么在第二步给成员变量赋值的时候会自动调用willChangeValueForKey:和didChangeValueForKey: 相当于手动触发了KVO。综上所述KVC是可以触发KVO的