KVO 的实现原理

在 Objective-C 中,KVO(Key-Value Observing)是通过运行时机制实现的。KVO 的底层主要依赖于 Objective-C 的消息机制和动态分发。下面将详细介绍 KVO 的底层实现原理,并提供简单的示例代码。

KVO 的实现原理

动态方法交换:当我们使用 KVO 时,系统会动态地为被观察的对象的属性生成一个子类 以NSKVONotifying_ + 类名,该子类重写了 getter 和 setter 方法。这个子类会在属性值被修改时发送通知。

通知机制:当属性值发生改变时,系统通过观察者模式通知所有注册的观察者。

消息转发:KVO 利用 Objective-C 的消息传递机制来实现对属性变化的监听和通知。


// 1. 定义被观察者
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end
@implementation Person @end

// 2. 观察者类
@interface ViewController ()
@property (nonatomic, strong) Person *person;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.person = [[Person alloc] init];
    self.person.name = @"Initial";

    // 3. 注册观察者 (监听 name 属性变化)
    [self.person addObserver:self
                  forKeyPath:@"name"
                     options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                     context:nil];
}

// 4. 监听回调
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
    if ([keyPath isEqualToString:@"name"]) {
        NSLog(@"旧值: %@, 新值: %@", change[NSKeyValueChangeOldKey], change[NSKeyValueChangeNewKey]);
    }
}

// 5. 移除观察者 (非常重要!)
- (void)dealloc {
    [self.person removeObserver:self forKeyPath:@"name"];
}
@end

手动关闭 KVO

重写这个方法
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
    return NO;
}

如果关闭后还想要手动触发 KVO 需要手动调用在变量setter的前后 主动调用 willChangeValueForKey:和didChangeValueForKey:


[self.person willChangeValueForKey:@"name"];
    self.person.name = @"Terry";
    [self.person didChangeValueForKey:@"name"];

KVO 注意事项

1.添加观察和移除观察需要成对出现

2.后续如果重构 Person 类,修改 name 属性,变成了 nickName,那么对应的 KeyPath 也要修改

发表回复