KVC和KVO

315 阅读2分钟

KVC

键值编码(Key-Value Coding)是Cocoa的一个特性,它允许你通过对象名设置和获取对象的值。

KVC特性

  • 如果尝试给一个并不存在于你定义的类的键设置一个值,该KVC系统将会抛出一个异常,因为运行时不知道将该值存储在哪里。
  • 在KVC中没有访问保护,当私有变量被访问时,KVC依然有效。

KVC不是旨在更换访问方法,而是提供一个更为灵活的方式设置和获取对象的值。

KVO

在MVC模式下,控制器如何得知何时更新视图?有两种选项:

  1. 反复检查模型,观察是否有任何更改。
  2. 等待模型向控制器发送通知。

第一种选项的实现最简单,创建一个定时器,定期获取模型中的最新值,并将其提供给视图。(浪费CPU资源)

要解决此问题,Cocoa提供了一种功能,KVO。KVO允许对象注册为当另一个对象更改它的一个属性的值时收到通知。

KVO有助于简化注册通知的过程以及通知任何需要被告知变化的对象。任何对象的任何属性都可以被观察,只要该属性的名称符合KVO。(前提是执行了setter方法或者使用了KVC赋值)。

添加观察者:

[self.model addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];

当属性发生变化时,系统会回调该方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"title"] && (object == self.model)) {
    // 获取新值,更新label。
    
        NSString *newTitle = [change objectForKey:NSKeyValueChangeNewKey];
        self.textLabel.text = newTitle;
        
        NSString *oldTitle = [change objectForKey:NSKeyValueChangeOldKey];
        NSLog(@"%@", oldTitle);
    }
}

另外,如果不使用OC属性,或者重写了一个属性的setter方法,则需要手动通知系统所做的更改。

- (void)setTitle:(NSString *)title {
    [self willChangeValueForKey:@"title"];
    _title = title;
    [self didChangeValueForKey:@"title"];
}