KVC
的全称是Key-Value Coding
,也就是键值编码
,咱们能够经过一个key来设置或获取某个属性的值。KVC
所用到的API以下:bash
// 经过key设置属性值
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
// 经过key获取属性值
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key;
复制代码
咱们看到设置和获取属性值的方法都有2个,一个是key
一个是keyPath
这两个有什么区别呢?直接看下面示例吧,咱们先定义以下2个类:ui
// Dog类
#import <Foundation/Foundation.h>
@interface Dog : NSObject
@property (nonatomic , assign) NSInteger age;
@end
// Student类
#import <Foundation/Foundation.h>
#import "Dog.h"
@interface Student : NSObject
@property (nonatomic , strong) NSString *name;
@property (nonatomic , strong) Dog *dog;
@end
复制代码
若是咱们要设置或获取Student
实例对象的name
属性值,经过key
或keyPath
方式都是同样的:编码
- (void)test{
self.stu1 = [[Student alloc] init];
self.stu1.dog = [[Dog alloc] init];
[self.stu1 setValue:@"Jack" forKey:@"name"];
NSLog(@"经过key的方式--%@",[self.stu1 valueForKey:@"name"]);
[self.stu1 setValue:@"Bob" forKeyPath:@"name"];
NSLog(@"经过keyPath的方式--%@",[self.stu1 valueForKeyPath:@"name"]);
}
复制代码
可是若是咱们要设置或获取Student
实例对象的dog
的age
属性值,那就只能经过keyPath
的方式了。此时若是仍是使用key
的方式设置属性值的话就会抛出setValue:forUndefinedKey:
的异常。atom
- (void)test{
self.stu1 = [[Student alloc] init];
self.stu1.dog = [[Dog alloc] init];
[self.stu1 setValue:@5 forKeyPath:@"dog.age"];
NSLog(@"%@",[self.stu1 valueForKeyPath:@"dog.age"]);
}
复制代码
咱们以setValue:forKey:
为例,KVC
设置属性值的整个流程以下图所示: spa
[self.stu1 setValue:@"Jack" forKey:@"name"];
这句代码,其底层执行流程以下:
self.stu1
的isa
指向的类对象,在类对象的方法列表中按照setName
、_setName
的顺序进行查找(也就是先查找看有没有setName
这个方法,没有的话再查找有没有_setName
方法)。Student
类的+ (BOOL)accessInstanceVariablesDirectly;
方法。若是返回值是YES
就表示容许直接访问类的成员变量,返回NO
表示不容许。这个方法是须要咱们在Student
类中重写的,由开发者来决定是否容许访问成员变量,若是不重写,默认是返回YES。NO
,那会直接抛出异常setValue:forUndefinedKey:
。YES
的话,那就会按照_name
、_isName
、name
、isName
这样一个顺序来查找类对象中的成员属性列表,若是找到了就直接赋值;若是没有找到就抛出异常setValue:forUndefinedKey:
。KVC
获取属性值的流程图以下: code
好比咱们执行[self.stu1 valueForKey:@"name"];
这句代码,其底层执行流程以下:cdn
getName
、name
、isName
、_name
的顺序进行查找。Student
类的+ (BOOL)accessInstanceVariablesDirectly;
方法,看其返回的是YES仍是NO;NO
,就直接抛出异常valueForUndefinedKey:
。YES
,就会按照_name
、_isName
、name
、isName
这样一个顺序来查找类对象中的成员属性列表,若是找到了就直接取值;若是没有找到就抛出异常valueForUndefinedKey:
。