1、KVO的定义(Key-Value Observing)
俗称键值监听。它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
KVO是“观察者”设计模式的一种应用,利用它可以很容易实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器的视图组件就会被激发,激发时就会回调监听器自身。这种模式有利于两个类间的解耦合,尤其是对于业务逻辑与视图控制 这两个功能的解耦合。
和KVC类似,在ObjC中要实现KVO则必须实现NSKeyValueObServing协议,但不用担心,因为NSObject已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO.
KVO常用的方法
1>注册指定Key路径的监听器
- (void)addObserver:(NSObject )observer forKeyPath:(NSString )keyPath
options:(NSKeyValueObservingOptions)options context:(void *)context
相关参数:
observer:观察者,也就是KVO通知的订阅者。订阅着必须实现
observeValueForKeyPath:ofObject:change:context:方法
keyPath:描述将要观察的属性,相对于被观察者。
options:KVO的一些属性配置;有四个选项。
options所包括的内容:
NSKeyValueObservingOptionNew:change字典包括改变后的值
NSKeyValueObservingOptionOld: change字典包括改变前的值
NSKeyValueObservingOptionInitial:注册后立刻触发KVO通知
NSKeyValueObservingOptionPrior:值改变前是否也要通知(这个key决定了是否在改变前改变后通知两次)
context: 上下文,这个会传递到订阅着的函数中,用来区分消息,所以应当是不同的。
2、KVO的本质就是通过重写setter方法来实现的
KVO的本质是通过重写setter方法来实现的,Objective-C是一门动态的语言,苹果在底层帮我生成了一个被观察对象类的子类,假如当前类是Apple类,通过运行时机制,生产了一个叫做NSKVONotifying_Apple的子类,让后将被观察者对象(apple)的isa指针指向新创建的类,这样,在子类中重写setter方法,并且在setter方法之中通过发送消息告诉观察者所观察的对象的属性值发生了变化,这样就可以根据变化做对应的处理。
3、iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)
3.1、利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类;
3.2、当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数
3.2.1、先调用willChangeValueForKey;
3.2.2、接着调用父类原来的setter方法;
3.2.3、最后调用didChangeValueForKey,其内部会触发监听器(Oberser)的监听方法(observerValueForKeyPath:ofObject:change:context:);
4、如何手动触发KVO?
手动调用willChangeValueForKey: 和 didChangeValueForKey:
5、直接修改成员变量会触发KVO么?
不会触发KVO
6、通过KVC修改属性会触发KVO么?
会触发KVO,KVC在修改属性时,会调用willChangeValueForKey: 和 didChangeValueForKey:方法;
7、KVC的赋值和取值过程是怎样的?原理是什么?
KVC赋值(setValue:forKey:)流程图7.1、首先会按照setKey、_setKey的顺序查找方法,若找到方法,则直接调用方法并赋值; 2、未找到方法,则调用+ (BOOL)accessInstanceVariablesDirectly; 3、若accessInstanceVariablesDirectly方法返回YES,则按照_key、_isKey、key、isKey的顺序查找成员变量,找到直接赋值,找不到则抛出异常; 4、若accessInstanceVariablesDirectly方法返回NO,则直接抛出异常;
KVC取值(valueForKey:)流程图7.2、首先会按照getKey、key、isKey、_key的顺序查找方法,找到直接调用取值
7.3、若未找到,则查看+ (BOOL)accessInstanceVariablesDirectly的返回值,若返回NO,则直接抛出异常;
7.4、若返回的YES,则按照_key、_isKey、key、isKey的顺序查找成员变量,找到则取值;
7.5、找不到则抛出异常;
网友评论