在开发中,我们可以通过使用 KVC 的方式来对某个对象的属性进行赋值/取值操作。
经常会用到以下 API:
// 设置值
- (void)setValue:(nullable id)value forKey:(NSString *)key;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
// 获取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;
- (nullable id)valueForKey:(NSString *)key;
1、赋值操作
KVC的调用原理:
如果我们给某个类定义一个属性,那么编译器会自动生成getter和setter方法,如果通过KVC给该属性进行赋值操作,默认会调用setter方法进行赋值,但是这不能完全搞清楚KVC是如何工作的。
现在我们定义一个Person类,但是我们并不给Person定义任何的属性,接下来创建person对象,通过KVC的方式给person的age属性进行赋值操作。
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc] init];
[person setValue:@(40) forKey:@"age"];
}
return 0;
}
接下来是执行顺序,去Person类中查找有没有- (void)setAge:
方法,如果有那么就进行赋值操作;如果没有再去查找有没有- (void)_setAge:
方法,如果有就进行赋值的操作,如果以上2个方法都没找到,那么就会调用- (Bool)accessInstanceVariablesDirectly
方法,该方法是询问是否可以直接访问成员变量,返回NO就直接抛出异常未定的key,返回YES(如果不实现该方法默认返回就是YES),那么就直接去成员变量中按顺序查找以下成员变量:_age
、_isAge
、age
、isAge
。如果找到4个成员变量中的1位,那么就进行赋值,否则抛出异常未定义的key。
2、取值操作
KVC 的取值操作也会按照一定的顺序进行操作的。
在取值的过程中,按照-(int)getAge
、-(int)age
、-(int)isAge
、-(int)_age
顺序进行,看有没有实现这4个方法中的其中1个,如果有那么调用,如果没有实现上面的4个方法,继续查看 + (BOOL)accessInstanceVariablesDirectly
方法的返回值是否为 YES,如果为NO,直接抛出异常,如果为YES,那么就去按顺序查找Person的成员变量是不是_age
,_isAge
、age
、isAge
中的一个,如果有4个成员变量中的1个,那么就取他们的值。