KVO与KVC原理笔记

365 阅读3分钟

KVO的实现原理

当我们对A类添加监听的时候,系统会自动生成一个NSKVONotifying_A的子类,这个类重写了A的class、superclass、deealloc方法和该属性的Set方法,同时A类的对象的isa指针指向了该虚拟子类。当监听属性改变的时候系统调用NSSetobjectValueandNotify,这个方法的执行流程是(willchangeValueforkey->改变父类的值->didchangeValueforkey->observeValueForKey:ofObject:change:context:),如果设置automaticallyNotifiesObserversForKey:(NSString *)key为NO的时候则需要手动触发KVO即手动调用willchangeValueforkey和didchangeValueforkey.

func _NSSetObjectValueAndNotify {
    ...
    willchangeValueforkey
    ...
    "
    objc_msgSendSupper '改变父类的值(猜测这样实现)
    "
    ...
    didchangeValueforkey
    ...
    observeValueForKey:ofObject:change:context: 
}

Q1: 为什么重写系统的class/superclass、deealloc方法

因为该子类为系统自动生成苹果想伪装成并没有这个类 所以重写class/superclass ,但是调用 objc_getClass()这个方法时候依然会暴露,因为这个方法是调用调用对象的isa指针指向。dealloc则是系统还有一些其他的事情处理

Q2:为什么KVO要实现一个子类

KVC是什么,他是如何实现的

KVCKVC是由NSKeyValueCoding非正式协议实现的一种机制,对象采用该协议来提供对其属性的间接访问。当一个对象符合键值编码时,它的属性可以通过一个简洁、统一的消息传递接口通过字符串参数来寻址。这种间接访问机制补充了实例变量及其关联的访问方法所提供的直接访问。

valueForkey的查找流程

  1. 在实例中搜索找到的类里面的相关方法,其名称依次为get<Key>, <key>, is<Key>, or _<key>。如果找到,则调用它,并继续执行步骤5的结果。否则继续下一步。
  2. 如果没有找到那么搜索countOf<Key> and objectIn<Key>AtIndex:,如果找到了其中的第一个和另外两个中的至少一个,则创建一个collection代理对象,该对象响应所有NSarray方法并返回该对象, 如果没有找到数组相关方法那么搜索countOf<Key>, enumeratorOf<Key>, and memberOf<Key>:,如果实现了其中一个则该对象响应所有Set方法的,
  3. 如果上述方法都没有找到那么判断accessInstanceVariablesDirectly 属性是否为yes,如果为yes则查找**_<key>, _is<Key>, <key>, or is<Key>**属性,如果找到直接返回变量值
  4. 如果都没找到那么且accessInstanceVariablesDirectly为false,那么执行valueForUndefinedKey:方法,调用valueForUndefinedKey:,默认情况下,这会引发异常,但NSObject的子类可能提供关键的特定行为

setValueForkey的实现

set value:for key:的默认实现:给定key和value参数作为输入,尝试在接收调用的对象内,使用以下过程将名为key的属性设置为value(对于非对象属性,则设置未包装的value版本,如表示非对象值:

  1. 按此顺序查找名为set<key> 和 **_set<key>**的第方法。如果找到了,使用value值调用它并完成。
  2. 如果找不到简单访问器,并且类方法accessInstanceVariablesDirectly返回Yes,则按该顺序查找名为 _<key>、_is<key>、<key>或is<key>的实例变量。如果找到,直接用value设置。
  3. 在找不到方法或实例变量时,调用setValue:ForUndefinedKey:。默认情况下,这会引发异常,但NSObject的子类可能提供关键的特定行为。