- (id)mx_valueForKey:(NSString *)key { // 1 - 安全校验 if (key == nil || key.length == 0) { returnnil; } // 2 - getter 方法检查和调用 NSString *getKeyM = [NSString stringWithFormat:@"get%@", key.capitalizedString]; NSString *isKeyM = [NSString stringWithFormat:@"is%@", key.capitalizedString]; NSString *_keyM = [NSString stringWithFormat:@"_%@", key]; NSString *countOfKey = [NSString stringWithFormat:@"countOf%@", key.capitalizedString]; NSString *objectInKeyAtIndex = [NSString stringWithFormat:@"ObjectIn%@AtIndex:", key.capitalizedString]; NSArray *methodNames = @[getKeyM, isKeyM, key, _keyM]; for(NSString *name in methodNames) { id value = [self checkPerformSelector: name]; if (value != nil) { return value; } } if ([self respondsToSelector:NSSelectorFromString(countOfKey)]) { if ([self respondsToSelector:NSSelectorFromString(objectInKeyAtIndex)]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" int num = (int)[self performSelector:NSSelectorFromString(countOfKey)]; NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:1]; for(int i = 0; i < num; i++) { id object = [self performSelector:NSSelectorFromString(objectInKeyAtIndex) withObject:@(i)]; #pragma clang diagnostic pop [mArray addObject:object]; } } } // 3 - 检查 accessInstanceVariablesDirectly if (![self.class accessInstanceVariablesDirectly]) { @throw [NSException exceptionWithName:@"MXUnknownKeyException" reason:[NSString stringWithFormat:@"[%@ valueForUndefinedKey:]: this class is not key value coding-compliant for the key name.", self] userInfo:nil]; } // 4 - 成员变量查找 NSString *_key = [NSString stringWithFormat:@"_%@", key]; NSString *_isKey = [NSString stringWithFormat:@"_is%@", key.capitalizedString]; NSString *isKey = [NSString stringWithFormat:@"is%@", key.capitalizedString]; NSArray *keys = @[_key, _isKey, key, isKey]; NSArray *names = [self getIvarListName]; for(NSString *key in keys) { if ([names containsObject:key]) { Ivar ivar = class_getInstanceVariable([selfclass], key.UTF8String); return object_getIvar(self, ivar); } } returnnil; }
总结
如果想详细的了解 Apple 的 KVC 源码实现细节,下面的两个资料是值得推荐的。掌握了 KVC 的底层原理,在使用 KVC 的时候,我们可以更加的得心应手、游刃有余。
GNUstep GNU 计划的项目之一。它将 Cocoa(前身为 NeXT 的 OpenStep )Objective-C软件库,部件工具箱(widget toolkits)以及其上的应用软件,以自由软件方式重新实现。它能够运行在类Unix 操作系统上,也能运作在 Microsoft Windows 上。
DIS_KVC_KVO, 这是根据IOS Foundation 框架汇编反写的 KVC,KVO 实现,可以在 mac, iOS 环境下运行调试。