KVC 原理
0x0. valueForKey:
当我们调用valueForKey:
时,内部会创建一个 NSKeyValueMethodGetter 对象,接着调用_NSGetUsingKeyValueGetter(self, getter)
方法。
伪代码如下:
- (id)valueForKey:(id)key {
Class cls = object_getClass(self);
OSSpinLockLock(&NSKVOLock);
NSKeyValueMethodGetter *getter = [NSObject _createValueGetterWithContainerClassID:cls key:key];
OSSpinLockUnlock(&NSKVOLock);
return _NSGetUsingKeyValueGetter(self, getter);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
那么是如何根据 key 找到对应的 value 呢?
结合官方文档和代码实践,绘制了具体查找流程,如下图:
0x1. setValue:forKey:
当调用setValue:forKey:
时,内部会创建一个 NSKeyValueMethodSetter 对象,接着调用_NSSetUsingKeyValueSetter(self, setter, value)
方法。
伪代码如下:
- (void)setValue:(id)value forKey:(NSString *)key {
Class cls = object_getClass(self);
OSSpinLockLock(&NSKVOLock);
NSKeyValueMethodSetter *setter = [NSObject _createValueSetterWithContainerClassID:cls key:key];
OSSpinLockUnlock(&NSKVOLock);
_NSSetUsingKeyValueSetter(self, setter, value);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
流程如下:
- 按顺序查找名字为
setKey:
或者_setKey:
方法,如果找到,则进行调用并将value
作为入参;
如果key
为属性名且不以下划线开头,则只会查找setKey:
方法;
如果key
为实例变量或者以下划线开头的属性名,则会先找setKey:
方法,没找到,再找_setKey:
方法
- 若步骤1未能处理,则进行当前步骤。会查看
accessInstanceVariablesDirectly
方法返回值,若为 YES,则会按顺序查找以下名字实例变量:_key
、_isKey
、key
、isKey
;若返回NO或者没找到这几个实例变量,则会抛出setValue:forUndefinedKey:
异常。
参考链接: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/