从学习Objective-C以来,有两个地方一直搞不明白。一个是KVO和KVC的应用和与Delegate的应用场景的区别,一个是Block的应用场景。总结起来就死对Objective-C的数据传送的应用不理解。乘着放假几天对这个知识点进行了一些学习和总结,学习了一个小demo,在这里记录一下自己的学习情况。
参考
- – http://yulingtianxia.com/blog/2014/05/12/objective-czhong-de-kvche-kvo/
- – http://objccn.io/issue-7-3/ #KVO
KVO简单使用
KVO(Key Value Observing),是观察者模式在Foundation中的实现
观察者模式,比较容易理解,就是一方对另一方观察,如果进行了改变,那么就要观察者接收到了消息就用进行相应的操作。在KVO中,总结起来就死以下几个操作。
- 当一个object有观察者的时候,动态创建这个object的子类。
- 对于每一个被观察的属性Property,重写他的set方法
- 在重写的set方法中,调用
- willChangeValueForKey
和- didChangeValueForKey
方法 - 当一个属性Property没有被观察的时候,删除重写的方法
- 当没有observer观察任何一个property的时候,删除动态创建的子类
使用的时候,主要通过以下几个方法来使用
addObserver:<#(NSObject *)#> forKeyPath:<#(NSString *)#> options:<#(NSKeyValueObservingOptions)#> context:<#(void *)#>
通过这个方法来为一个对象添加观察者,观察减值“key”,option是观察返回的类型字典,总共有以下几种
- NSKeyValueObservingOptionOld – 变化前的值
- NSKeyValueObservingOptionNew – 变化后的值
- NSKeyValueObservingOptionPrior – 值变化前进行通知
- NSKeyValueObservingOptionInitial – 在添加观察者的时候出发相关方法
context 是一个指针当observeValueForKeyPath:ofObject:change:context:
方法执行时context会提供给观察者。context可以是C指针或者一个对象引用,既可以当作一个唯一的标识来分辨被观察的变更,也可以向观察者提供数据。
当观察者接受到消息的时
当被观察的属性变更时,观察者会接到observeValueForKeyPath:ofObject:change:context:
消息,所有的观察者都必须实现这个方法。
观察者会被提供触发通知的对象和keyPath,一个包含变更详细信息的字典,还有一个注册观察者时提供的context指针。
关于change字典,总共包含以下五个键值
1 | NSString *const NSKeyValueChangeKindKey; |
- NSKeyValueChangeKindKey
指明了变更的类型,值为“NSKeyValueChange”枚举中的某一个,类型为NSNumber。
1 | enum { |
- NSKeyValueChangeNewKey
如果 NSKeyValueChangeKindKey
的值为 NSKeyValueChangeSetting
,并且 NSKeyValueObservingOptionNew
选项在注册观察者时也指定了,那么这个键的值就是属性变更后的新值。
对于 NSKeyValueChangeInsertion
或者NSKeyValueChangeReplacement
,如果 NSKeyValueObservingOptionNew
选项在注册观察者时也指定了,这个键的值是一个数组,其包含了插入或替换的对象
- NSKeyValueChangeOldKey
移除观察者
你可以通过发送removeObserver:forKeyPath:消息来移除观察者,你需要指明观察对象和路径
注意,在移除观察者之前,如果context是一个对象的引用,那么必须保持对它的强引用直到观察者被移除。
注册依赖键
有时候,有些属性的值取决于一个或者多个属性的值,一旦某个依赖的属性的值改变了,依赖它的属性的值需要被通知进行改变。
To - One
要触发to - one 关系,有两种方法
- 定义名称为
keyPathForValueAffecting<key>
方法 - 重写
keyPathForValueAffectingForKey:
方法
To - Many
由于keyPathForValueAffectingForKey
不支持包含to-many关系的keypath。如果一个类的属性对另一个类的多个属性有依赖关系的时候,必须通过其他方法来实现KVO。
将parent类作为所有children类的相关属性的观察者。此时必须注意如果将将child类添加或者删除的时候必须对parent类对child类的观察者添加或者删除。此时通过
observeValueForKeyPath:ofObject:change:context:
可以通过对被依赖属性的变化来更新依赖属性的值。Core Data中有另外一种实现观察者模式的方法,由于我还没有使用过Core Data,暂且不谈
调试KVO
在LLDB中,我们可以通过po [object observationInfo]
来获取观察者信息
#KVC
KVC简单使用
KVC即是键值编码。以字符串的形式向对象发送消息,这个字符串是我们关注的焦点。
基本调用是-valueForKey
和 -setValue:forKey
对于KVC,Cocoa自动放入和取出标量值(int,float和struct)放入NSNumber和NSValue中,当使用-setValue:forKey
的使用,他自动将标量值从这些对象中取出。
使用KVC访问属性的代价比直接使用存取方法要大,所以只有在需要的时候才使用。