关于KVO

KVO官方文档:点击这里

Key-value observing is a mechanism that allows objects to be notified of changes to specified properties of other objects.

Important: In order to understand key-value observing, you must first understand key-value coding.

Key-value observing简称KVO,是指当对象的指定属性发生改变时,能够通知别的对象的一种机制。

注意:如果想要了解KVO,首先需要了解KVC的机制。

1.KVO的三步骤

  1. 注册一个观察对象 addObserver:forKeyPath:options:context:
  2. 接收改变的通知的回调 observeValueForKeyPath:ofObject:change:context:
  3. 移除观察对象 removeObserver:forKeyPath:

addObserver:forKeyPath:options:context:

 - (void)registerAsObserverForAccount:(Account*)account {
    [account addObserver:self
              forKeyPath:@"balance"
                 options:(NSKeyValueObservingOptionNew |
                          NSKeyValueObservingOptionOld)
                 context:PersonAccountBalanceContext];
 
    [account addObserver:self
              forKeyPath:@"interestRate"
                 options:(NSKeyValueObservingOptionNew |
                          NSKeyValueObservingOptionOld)
                  context:PersonAccountInterestRateContext];
}
  1. account对象是被观察对象,观察account里边的属性是不是改变。
  2. self是观察对象。
  3. @“balance”是被观察的属性路径。
  4. options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld|NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionPrior,观察属性改变后的新值,属性改变前的旧值,属性的初始值。之后一个类型一般不会使用。
  5. context是一个标签,能够快速的区分观察者,被观察者及被观察的属性。需要开发者自己设置标签,快速定位减少判断。

observeValueForKeyPath:ofObject:change:context:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
 
    if (context == PersonAccountBalanceContext) {
        // Do something with the balance…
 
    } else if (context == PersonAccountInterestRateContext) {
        // Do something with the interest rate…
 
    } else {
        // Any unrecognized context must belong to super
        [super observeValueForKeyPath:keyPath
                             ofObject:object
                               change:change
                               context:context];
    }
}
  1. keyPath是被观察的属性路径。
  2. object是观察者对象。
  3. change是属性改变的回调信息。
  4. context:如上代码,用户自己设置的标签,便于快速定位需要观察的属性路径。

removeObserver:forKeyPath:

- (void)unregisterAsObserverForAccount:(Account*)account {
    [account removeObserver:self
                 forKeyPath:@"balance"
                    context:PersonAccountBalanceContext];
 
    [account removeObserver:self
                 forKeyPath:@"interestRate"
                    context:PersonAccountInterestRateContext];
}

当不再需要观察、或者观察者和被观察者被析构时,都要使用此方法来移除观察者。

2.自动通知

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
 
    BOOL automatic = NO;
    if ([theKey isEqualToString:@"balance"]) {
        automatic = NO;
    }
    else {
        automatic = [super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}

automaticallyNotifiesObserversForKey:这个方法是NSObject类的方法,默认返回是YES,当继承于NSObject类的子类通过三部曲都能够实现KVO的功能。如果在被观察的子类中重载此方法并且返回NO,则不会回调通知回调方法。

3.手动通知

- (void)setBalance:(double)theBalance {
    [self willChangeValueForKey:@"balance"];
    _balance = theBalance;
    [self didChangeValueForKey:@"balance"];
}

当实现了KVO的三部曲后,但是被观察者类中的automaticallyNotifiesObserversForKey:方法返回的是NO,不会对balance属性的改变进行回调。如果现在需要KVO的功能,我们可以使用如上代码手动开启KVO。在setter方法中实现代码。

KVO的使用

  1. KVO三部曲的实现


    图一

    图二

    图三
  2. 自动和手动通知


    图四

    图五
  3. 观察数组内容的改变


    图六

KVO的原理

自定义KVO

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容