返回
KVO keyPath 实现源码解析
IOS
2023-10-30 13:40:51
kvc 简介
KVO(key-value observing)是一种观察对象属性变化的机制,能够在属性值改变时自动调用相关方法,从而实现监听对象属性变化的功能。KVO 广泛应用于 Cocoa 开发中,比如自动更新 UI 和数据绑定。
实现 KVO 的关键步骤包括:给属性添加观察者、调用 KVO 方法监听属性变化、在属性值改变时调用观察者方法。
keyPath 实现源码解析
static Class _class_by_className(const char *name)
{
Class cls = objc_lookUpClass(name);
if (!cls) {
cls = objc_NSClassFromString(name);
}
return cls;
}
static inline Class
class_forKeyPath(const char *keyPath)
{
const char *current = keyPath;
while (*current == '.')
current++;
NSString *className;
if (current)
className = [NSString stringWithUTF8String:current];
else
className = [NSString stringWithUTF8String:"NSObject"];
return _class_by_className([className UTF8String]);
}
这段代码用于通过 keyPath 获取对应的类。它首先跳过 keyPath 中的第一个点,然后根据剩余的字符串构造一个类名,最后使用 objc_lookUpClass() 或 objc_NSClassFromString() 函数获取对应的类。
@implementation NSDictionary (NSString)
- (id) valueForKey:(NSString *)key
{
if (!key)
return nil;
NSString *classname = NSStringFromClass([self class]);
const char *class_name = classname.UTF8String;
if (class_name[0] == '_')
return nil;
Class class = class_forKeyPath(keyPath);
if (!class)
return nil;
NSMethodSignature *signature = [class methodSignatureForSelector:@selector(valueForKey:)];
if (!signature)
return nil;
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
if (!invocation)
return nil;
[invocation setSelector:@selector(valueForKey:)];
[invocation setTarget:self];
[invocation setArgument:&key atIndex:2];
[invocation invoke];
id result = nil;
[invocation getReturnValue:&result];
return result;
}
@end
这段代码是 NSDictionary 类实现的 valueForKey 方法。它首先检查 key 是否为 nil,如果是则返回 nil。然后它获取 NSDictionary 类的类名并检查它是否以“”开头。如果以“”开头,则返回 nil。接下来,它使用 class_forKeyPath() 函数获取 keyPath 对应的类。如果找不到对应的类,则返回 nil。
如果找到了对应的类,则获取该类的 valueForKey: 方法的签名。如果没有找到签名,则返回 nil。然后,它创建一个 NSInvocation 对象来调用 valueForKey: 方法。设置调用方法、调用对象和参数后,它调用 invoke 方法来执行该方法。
最后,它从 NSInvocation 对象中获取返回值并将其返回。