KVC 研究

2,591 阅读1分钟

setValue:forKey: 的调用流程

graph LR
A[setValue:forKey:] --> B[setKey:] 
subgraph set
B --> B1[setIsKey:]
end
B1 --> C{+accessInstanceVariablesDirectly}
C --> D[_key]
subgraph instance
D[_key] --> _isKey --> key --> E[isKey]
end
E --> F[setValue:forUndefinedKey:]

valueForKey: 的调用流程

graph LR
subgraph get
A[getKey] --> Ag[key] --> A1[isKey]
end
subgraph count
A1 --> countOfKey --> A2[objectInKeyAtIndex]
end
A2 --> A3{accessInstanceVariablesDirectly}
A3 --> A4[_isKey]
subgraph instance
A4 --> key --> A5[isKey]
end
A5 --> valueForUndefinedKey:

其它

  1. kvc 官方文档已经说的很明白,上述为主要流程,文档中还有其他小细节。

小细节

  1. setValue:forUndefinedKey: 被调用后会发生什么?

答:发生 NSUndefinedKeyException 崩溃,但是我们可以重写它。

  1. setNilForKey: 直接调用会发生什么?

Given that an invocation of -setValue:forKey: would be unable to set the keyed value because the type of the parameter of the corresponding accessor method is an NSNumber scalar type or NSValue structure type but the value is nil, set the keyed value using some other mechanism. The default implementation of this method raises an NSInvalidArgumentException. You can override it to map nil values to something meaningful in the context of your application.

  1. 哪些三方库中有使用到?

MJExtension 最后给属性赋值的时候使用到了,由于他使用的是 kvc,而 YYModel 使用的是对象的 setter 方法,所以他在最后的赋值阶段要比 YYModel 慢很多。

测试

KVC kvc = [[KVC alloc] init];

CFTimeInterval begin = CACurrentMediaTime();
for (int i = 0; i < 1000000; i ++) {
    [kvc setValue:@"123" forKey:@"abc"];
}
CFTimeInterval end = CACurrentMediaTime();
NSLog(@"---%f", end - begin); // 0.03

for (int i = 0; i < 1000000; i ++) {
    [kvc setAbc:@"123"];
}
CFTimeInterval end1 = CACurrentMediaTime();
NSLog(@"===%f", end1 - end); // 0.009

可以看出 kvc 的性能仅为直接调用 setter 方法效率的 1 / 3