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的三步骤
- 注册一个观察对象
addObserver:forKeyPath:options:context:
- 接收改变的通知的回调
observeValueForKeyPath:ofObject:change:context:
- 移除观察对象
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];
}
- account对象是被观察对象,观察account里边的属性是不是改变。
- self是观察对象。
-
@“balance”
是被观察的属性路径。 -
options
:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld|NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionPrior
,观察属性改变后的新值,属性改变前的旧值,属性的初始值。之后一个类型一般不会使用。 -
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];
}
}
-
keyPath
是被观察的属性路径。 -
object
是观察者对象。 -
change
是属性改变的回调信息。 -
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的使用
-
KVO三部曲的实现
-
自动和手动通知
-
观察数组内容的改变