iOS KVO (Key-Value Observing) 和 KVC (Key-Value Coding) 的原理

Key-Value Coding (KVC)

KVC 是一种访问对象属性的机制,它允许通过字符串键(key)间接访问属性,而不是直接调用存取方法或直接访问实例变量。KVC 为对象提供了一种通用的方法来访问和修改其属性。KVC 的常用方法有:

  • valueForKey::通过键名获取属性值。
  • setValue:forKey::通过键名设置属性值。

KVC 的实现原理:

  1. 查找顺序

    • 首先查找与键名同名的 getter 方法(如 keyisKey)。
    • 如果没有找到,查找 key_key 命名的实例变量。
    • 如果仍未找到,则调用 valueForUndefinedKey: 方法,默认实现会抛出异常。
  2. 设置值

    • 首先查找与键名同名的 setter 方法(如 setKey:)。
    • 如果没有找到,查找 key_key 命名的实例变量,然后直接访问它。
    • 如果仍未找到,则调用 setValue:forUndefinedKey: 方法,默认实现会抛出异常。

Key-Value Observing (KVO)

KVO 是一种观察某个对象属性变化的机制。当对象的属性发生变化时,KVO 会自动通知观察者。KVO 通过注册观察者来监听属性的变化。

KVO 的实现原理:

  1. 动态子类

    • 当一个对象的某个属性被观察时,KVO 动态创建该对象的子类,并重写属性的 setter 方法。
    • 在重写的 setter 方法中,先调用 willChangeValueForKey:,然后调用原始的 setter 方法,最后调用 didChangeValueForKey:
  2. 通知机制

    • willChangeValueForKey:didChangeValueForKey: 会在属性值变化前后发送通知。
    • 观察者通过实现 observeValueForKeyPath:ofObject:change:context: 方法来接收变化通知。

KVO 的注意事项:

  • KVO 只能观察符合 KVC 的属性。
  • 手动触发 KVO 通知时,需要在属性值变化前后分别调用 willChangeValueForKey:didChangeValueForKey:

以下是一个 KVO 和 KVC 的示例代码:

// Person.h
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end

// Person.m
@implementation Person
@end

// main.m
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *person = [[Person alloc] init];

        // KVC 访问属性
        [person setValue:@"Alice" forKey:@"name"];
        NSString *name = [person valueForKey:@"name"];
        NSLog(@"Name: %@", name); // 输出: Name: Alice

        // 注册 KVO 观察者
        [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

        // 修改属性触发 KVO
        person.name = @"Bob";

        // 移除 KVO 观察者
        [person removeObserver:self forKeyPath:@"name"];
    }
    return 0;
}

// 实现 KVO 回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"name"]) {
        NSLog(@"Name changed to: %@", change[NSKeyValueChangeNewKey]);
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容