kvc
就是key value coding
,在Foundation
框架中有一个类叫NSKeyValueCoding
, 在这里有关于kvc的一切。
- 关于
kvc
的使用,常用的就是这四个方法:
- (nullable id)valueForKey:(NSString *)key;
- (void)setValue:(nullable id)value forKey:(NSString *)key;
- (nullable id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
- 以及一些其他不常用的方法:
- (nullable id)valueForUndefinedKey:(NSString *)key;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
- (void)setNilValueForKey:(NSString *)key;
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
- 使用方法没什么可说的,说说kvc的底层实现原理:
这里有一个关键的属性:
@property (class, readonly) BOOL accessInstanceVariablesDirectly;
这个属性字面翻译下就是:能否直接访问实例变量?
这个属性的注释:
Return YES if -valueForKey:, -setValue:forKey:, -
mutableArrayValueForKey:, -storedValueForKey:,
-takeStoredValue:forKey:, and -takeValue:forKey:
may directly manipulate instance variables
when sent to instances of the receiving class, NO otherwise.
The default implementation of this property returns YES.
很easy的英文,大概翻译一下:
如果一个对象想通过调用这些方法-valueForKey:, -setValue:forKey:, -
mutableArrayValueForKey:, -storedValueForKey:,
-takeStoredValue:forKey:, and -takeValue:forKey:来访问自身的实例变量,则返回yes,反之no
默认返回yes
当一个对象object
调用setValue:forKey:
or setValue:forKeyPath:
的时候,首先会查找这个key的set方法:-(void)setKey:
还有另外一个加下划线_
的-(void)_setKey:
,找到两个方法重的任一则直接调取完成赋值。如果找不到则去查询accessInstanceVariablesDirectly
方法是否返回yes
, 如果是no
的话,就看是否实现了- (void)setValue:forUndefinedKey:
,如果没实现,则crash
报错Terminating app due to uncaught exception NSUnknownKeyException
; 如果accessInstanceVariablesDirectly
返回yes
, 则可以访问实例变量了,依次查找key
、_key
、 isKey
、 _isKey
是否存在,如果有的话,直接完成赋值,如果没有则走到了- (void)setValue:forUndefinedKey:
。
当一个对象object
调用valueForKey:
or valueForKeyPath:
的时候,首先会查找这个key的get方法:getKey:
、-_getKey:
、_key
、key
,找到两个方法重的任一则直接调取完成读取。如果找不到则去查询accessInstanceVariablesDirectly
方法是否返回yes
, 如果是no
的话,就看是否实现了- valueForUndefinedKey:
,如果没实现,则crash
报错Terminating app due to uncaught exception NSUnknownKeyException
; 如果accessInstanceVariablesDirectly
返回yes
, 则可以访问实例变量了,依次查找key
、_key
、 isKey
、 _isKey
是否存在,如果有的话,直接完成取值,如果没有则走到了- valueForUndefinedKey:
,逻辑跟以上大同小异。
简单的画个图演示下(只画一个
):