利用键值观察,你可以自动观察其他对象的变化。因此,当一个对象改变状态时你就会得到通知,比如用户通过应用中的设置面板g改变了设置时。通过键值观察,利用该设置的窗体和其他对象在用户改变设置时,都可以自动得到通知。你不需要手动告诉其他对象进行更新。他们会自动收到新值并执行适当的操作。这是极其强大的。设置是该技术最强大的应用之一。此外,Cocoa框架中的核心数据和其他技术也利用了键值观察实现了一些奇妙的功能。
要使用键值观察,被观察的对象必须对所观察的特性使用符合KVC标准的存取器方法。第二,想要观察变化的对象,也就是观察者,必须实现一个接收通知的特殊方法。该方法是-observeValue:forkeyPath:ofObject:change:context:。该方法在值变化时被调用并可以配置成同时接收新值和原值以及其他自定义的信息。
最后,观察者通过调用-addObserver:forKeyPath:options:context:方法针对被观察对象进行注册。调用该方法,告诉对象要观察的KVC键值路径以及希望看到的变化,并提供一个在收到变化通知时可以传回的上下文对象。
但观察者完成这些配置后,键路径指定的属性的任何变化都可以自动调用观察者的回调方法。在观察者完成被观察对象的观察后,必须将自己移除。如果没有做到这一点并且观察者之后就释放了,将来向该观察者发送消息通知时可能会导致应用崩溃。
注册成为观察者
针对于要观察的对象调用-addObserver:forKeyPath:options:context:方法。observer参数通常是self这是在被观察值变化时收到通知的对象。键路径参数指定想要观察的特性的键路径。options参数指定一些标记来告诉KVO你希望变化如何传给你。这些值可以通过|操作符进行或操作。
NSKeyValueObservingOptionNew 作为变更信息的一部分发送新值
NSKeyValueObservingOptionOld 作为变更信息的一部分发送旧值
NSKeyValueObservingOptionInitial 在观察者注册时发送一个初始更新
NSKeyValueObservingOptionPrior 在更变前后分别发送更变,而不只在更变后发送一次
上下文参数是一个在KVO系统中无变更传递的void*参数,并且会在有变更通知时传回给你的对象。本质上,就KVO而言,该参数是不透明的数据块,并且完全是和实现相关的。任何从此传人参数的都会无变更传递的。(不要将一些存储在栈上的值传递给该参数。跟垃圾回收有关系)
定义KVO的回调
使用KVO第二步是回调,-observerValue:forKeyPath:ofObject:change:context:。该方法自动传入一个对象参数,告诉你哪个对象想你发送了通知。通知对键值路径的传入值使用-isEquals方法,你可以准确地确定对象的什么特性发生了改变。Key参数仅仅是一个字符串,和对KVC使用时一样。因此,你可以使用NSString方法-isEqualToString:来确定该通知所对应的键值路径。实际变化通过change参数传递给你。该参数是字典对象,包含了注册观察者时所请求的变化信息相关的键和值。
NSKeyValueChangeKindKey 指定变化类型的NSNumber
NSKeyValueChangeNewKey 新值
NSKeyValueChangeOldKey 原值
NSKeyValueChangeIndexeskey 如果NSKeyValueChangeKindKey是NSKeyValueChangeInsertion、 NSKeyValueChangeRemoval、NSKeyValueChangeReplacement 之一,该值就包含变化值的索引
NSKeyValueChangeNotificationIsPriorKey 和NSKeyValueChangeOptionPrior 结合使用来表示这是 之前的通知
NSKeyValueChangeKindKey指定了接收到变化类型
NSKeyValueChangeSetting 指定该值被设置
NSKeyValueChangeInsertion 指定这些值插入到集合或者一对多的关系
NSKeyValueChangeRemoval 指定这些值在一对多的关系中被移除
NSKeyValueChangeReplacement 指定这些值在一对多的关系中被代替
移除观察者
在结束对一个对象变化的观察后,需要移除观察者,如果不这样,可能会崩溃。
调用的方法就是-removeObserver:forKeyPath:,观察者作为第一个参数,观察的路径是第二个参数。
实现手动通知
所有的这些通知都是自动发生的,如果想一次性进行很多更变,可能将想要的这些变化打包一起发送。这种情况只能用手动通知。
必须重写+automaticallyNotifiesObserversForKey:
如果想手动通知所发生的变化,必须在变化之前调用方法-willChangeValueForKey:然后在变化之后调用方法-didChangeValueForKey:
(来自:学好Objective -C)