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

那么是如何根据 key 找到对应的 value 呢? 结合官方文档和代码实践,绘制了具体查找流程,如下图: kvc

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

流程如下:

  1. 按顺序查找名字为setKey:或者_setKey:方法,如果找到,则进行调用并将value作为入参;

如果key为属性名且不以下划线开头,则只会查找setKey:方法;

如果key为实例变量或者以下划线开头的属性名,则会先找setKey:方法,没找到,再找_setKey:方法

  1. 若步骤1未能处理,则进行当前步骤。会查看accessInstanceVariablesDirectly方法返回值,若为 YES,则会按顺序查找以下名字实例变量:_key_isKeykeyisKey;若返回NO或者没找到这几个实例变量,则会抛出setValue:forUndefinedKey:异常。

参考链接: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/

最后更新: 2/1/2021, 5:39:58 PM