定义
KVC(key-value coding,键值编码):可以允许开发者通过key名直接访问对象的属性,或者给对象的属性赋值,这样就可以在运行时动态地访问和修改对象的属性,而不是在编译时就确定
方法全览
在开发者手册中找到NSKeyValueCoding
KVC:一种可以通过名称或键间接的访问对象属性的机制
- 取值方法
- 设值方法
accessInstanceVariablesDirectly
该方法返回一个布尔值,该值指示在找不到属性的访问器方法时,键值编码方法是否应直接访问相应的实例变量
- 属性验证
常用方法
key和keyPath
- key:键
- 只能接受当前类所具有的属性,不管是自己的,还是从父类继承过来的都可以接受
- keyPath:键路径
- 除了能接受当前类的属性,还能接受当前类的属性的属性,即可以接受关系链
取值方法
- (nullable id)valueForKey:(NSString *)key; //通过key来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath; //通过keyPath取值
基于getter取值的底层实现
设值方法
基于setter设值的底层实现
KVC内部在修改成员变量的同时是会主动调用willChangeValueForKey:
和didChangeValueForKey:
,所以会触发KVO
注意⚠️:直接修改成员变量是不会触发KVO的,因为只是单纯的赋值,不会调用setter方法
属性验证
//key
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//keyPath
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;
该方法默认去探索类里面是否有一个这样的方法
- 如果有,就调用这个方法来返回
- 如果没有,就返回YES
处理异常
常见的异常有两种:传入了错误的key 和 传入了nil
-
传入了错误的key
可以通过重写下面两个方法,
- (nullable id)valueForUndefinedKey:(NSString *)key; - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
-
传入了nil
如果不小心传入了nil,KVC会调用
setNilValueForKey:
方法,这个方法默认会抛出异常,所以一般我们就重写这个方法-(void)setNilValueForKey:(NSString *)key{ NSLog(@"不能将%@设成nil",key); }
处理非对象
valueForKey:
总是返回一个id
对象,如果原本的变量类型是值类型或者结构体,返回值会封装成NSNumber
或者NSValue
对象,这两个类会处理从数字,布尔值到指针和结构体任何类型,然后需要开发者手动转换成原来的类型setValue:forKey:
:不会自动封装成对象,必须手动将值类型转换成NSNumber
或者NSValue
类型,才能传递过去
KVC与容器
引言
- 对象的属性可以是一对一的,可以是一对多的
- 一对多的属性要么是有序的(数组),要么是无序的(集合)
KVC与有序容器
取值方法:该方法返回一个可变有序数组
//key
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//keyPath
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
底层实现原理
KVC与无序容器
取值方法:方法返回一个可变的无序数组
//key
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
//keyPath
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;
底层实现
KVC适用场景
动态取值设值
Model和字典的转换
在对象调用setValuesForKeysWithDictionary:
方法时,可以传入一个包含key
、value
的字典进去,KVC
可以将所有数据按照属性名和字典的key
进行匹配,并将value
给User
对象的属性赋值
用KVC来访问和修改私有变量
KVC
本质上是操作方法列表以及在内存中查找实例变量,因此我们可以利用这个特性来访问类的私有变量
这个操作对readonly
的属性,@protected
的成员变量,都可以正常访问
如果不想让外界访问类的成员变量,则可以将accessInstanceVariablesDirectly
属性赋值为NO
修改一些控件的内部属性
参考博客: