iOS KVO的实现原理

来源:互联网 发布:javascript 转义符 编辑:程序博客网 时间:2024/05/17 04:13

一、KVO是什么

  • KVO是OC的一种观察者设计模式,另一种是通知机制(notification)
  • KVO的机制:指定一个被观察对象,当该对象某个属性发生变化时,观察对象会获得通知,并作出相应动作,并且被观察的对象不需要添加任何额外的代码

在MVC设计架构下,KVO机制通常实现数据模型和视图之间的通讯,这样可以保证数据和视图显示达到同步


二、实现原理

KVO的实现依赖于OC强大的运行时Runtime。

原理:
当观察某对象时,KVO动态创建该对象的子类,并重写子类被观察属性setter方法,随后通知观察者该属性的变化状况。

实现过程:

Apple使用isa混写(isa-swizzling)来实现KVO。
当观察对象A时,KVO动态创建了新的名为NSKVONotifying_A的新类,该类时为对象A的子类,并且KVO重写了新类的观察属性的setter方法,setter方法负责在调用原setter方法之前和之后,通知所有观察者该属性的变化情况

  • NSKVONotifying_A

每个对象内部都有isa指针,这个指针指向该对象的类,在KVO机制中,该isa指针被修改为指向系统新创建的子类NSKVONotifying_A,那么当被观察者修改被检测的属性的值时候,就会调用KVO重写的setter方法,从而激活键值通知机制,实现当前类属性改变的监听。

所以当我们从应用层面上来看,并没有意识到有新类的出现,这是apple隐瞒类对KVO的底层实现过程,而我们还以为是原来的类,但是此时如果我们创建一个新的名为“NSKVONotifying_A“的类时,就会发现系统运行到注册KVO的那段代码时,程序发生崩溃,因为系统在注册监听的时候动态创建了名为NSKVONotifying_A的中间类,并指向这个中间类了

  • 子类重写setter方法

KVO的键值观察通知依赖于NSObject的两个方法:willChangeValueForKey:和didChangeValueForKey:,在存取数值的前后分别调用2个方法;
被观察属性发生改变之前,willChangeValueForKey:被调用,通知系统该keyPath的属性值即将变更;当改变发生后,didChangeValueForKey:被调用,通知系统keyPath的属性值已经发生改变,之后,observeValueForKey:ofObject:change:context:也会被调用。
注意:重写观察属性的setter方法这种继承方式的注入是在运行时而不是编译时实现的

KVO为子类的观察者属性重写调用存取方法的工作原理在代码中相当于:

-(void)setName:(NSString *)newName{    [self willChangeValueForKey:@"name"];    //KVO在调用存取方法之前总调用    [super setValue:newName forKey:@"name"]; //调用父类的存取方法    [self didChangeValueForKey:@"name"];     //KVO在调用存取方法之后总调用}

三、特点

观察者观察的是属性,只有遵循KVO变更属性值的方式才会执行KVO的回调方法,例如执行setter方法、KVC方式赋值等,如果赋值没有通过KVO来变更属性值,而是直接修改属性对应的成员变量,例如:仅调用_name=@”newName”,这时是不会触发KVO机制,更加不会调用回调方法的,因此,使用KVO机制的前提是遵循KVO属性设置方式来变更属性值。


四、拓展

1、和KVC的比较?

  • KVC,即Key-Value-Coding,是一个非正式协议,使用字符串(key)来访问一个对象实例变量的机制
  • KVO,即Key-Value-Observing,它提供一种机制,当被观察者的属性值更改时,观察者就会接收到通知

2、和通知的区别?

  • 相比于KVO重写setter时调用 observeValueForKey:ofObject:change:context:方法,通知要多发送通知操作,例如重写类的setter方法,使用通知也可以实现类似KVO的监听
  • 两者都是一对多,两者相比,通知的使用率要高得多,因为通知监听不局限于属性的变化,还可以是状态的变化,监听范围广,例如键盘的出现、app进入后台等,使用也更灵活方便
  • KVO的过程其实包括了通知这一环,只不过由系统来完成了

3、和delegate的不同?

KVO、通知、delegate三者都是类与类之间的通信,但是delegate不同的是:

  • KVO和通知都负责发送和接收通知,剩下的事情都由系统来完成,所以不用返回值,而delegate则需要协议和代理对象来关联
  • delegate适用于一对一,KVO和通知则适用于一对多情况

4、涉及的技术

KVC和KVO实现的根本是OC语言的动态性和运行时runtime,以及访问器方法的实现


五、总结

相比如其他消息回调的方式,KVO机制的实现更多的依赖于系统支持,它能够提供被观察属性的newValue和oldValue;但是由于需要创建对应的子类、重写setter方法等,内存消耗也是很大的,所以对于两个类之间的消息通信,我们应该根据实际应用的场景来选择通信方式

另外需要注意的是,由于这中继承方式的注入是在运行时而非编译时实现,所以当没有观察者时,KVO不会有任何开销,此时也根本就没有KVO代码存在,但是如果时委托和通知那还是需要开销,这也是KVO零开销观察的优势。


六、文章转载地址

iOS–KVO的实现原理与具体应用

原创粉丝点击