KVO和KVC

全称
  • KVO: Key-Value-Observer
  • KVC: Key-Value-Coding

KVO的使用

使用过程
  • 监听回调返回新值和旧值
    NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;

  • 添加监听
    [被监听的实例对象 addObserver:监听器 forKeyPath:属性 options:options context:nil]

  • 监听接收事件
    - (void)observeValueForKeyPath:(NSString*)keyPathofObject:(id)objectchange:(NSDictionaryid> *)changecontext:(void*)context{ NSLog(@"%@--%@--%@",object,keyPath,change); }

  • 记得添加监听和移除监听,需要配对使用

原理

测试类 Person

  1. 系统会生成NSKVONotifying_Person类,该类继承Person,并且将Person的isa指向NSKVONotifying_Person。

  2. NSKVONotifying_Person从写监控属性的setter方法,内部调用_assetXXXValueAndNotify();
    _assetXXXValueAndNotify内部实现:

    2.1 - (void)willChangeValueForKey:(NSString *)key;

    2.2- (void)didChangeValueForKey:(NSString *)key;

    2.3 didChangeValueForKey里面调用 [super didChangeValueForKey]时,会触发回调方法
    - (void)observeValueForKeyPath:(NSString*)keyPathofObject: (id)objectchange:(NSDictionaryid> *)changecontext:(void*)context

    通知开发者数据发生变化。

3.NSKVONotifying_Person内部还会从写 - (Class)class; 方法,目的是隐藏系统生成的类。

4.如果需要手动调用,只需要调用2个方法:
willChangeValueForKey
didChangeValueForKey
即可;
5.单纯使用KVO,访问成员变量person -> age = 10;是不会触发KVO监听的。

KVC setValueForKey: 和setValueForKeyPath:

假如Person对象有个属性叫age

setValueForKey
  • 可以对实例对象的某个属性赋值
setValueForKeyPath:入参是路径,
  • 可以对实例对象中的,某个对象的某个属性,进行赋值;例如入参可以是:person.data.num,就代表对person对象的data对象的num属性进行赋值

  • 可以访问对象的隐藏属性

  • 可以求最大最小值,再也不用手动遍历数组求值了

    求最大值:[array valueForKeyPath:@"@max.self"]

使用KVC赋值

例如Person中有一个age属性

  • 查找顺序
    1.setAge:
    2._setAge:

  • 假如上面2个方法都没有实现,则系统会调用是否允许直接访问成员变量方法:
    + (BOOL)accessInstanceVariablesDirectly
    如果返回NO,则系统调用setValue:forUndefineKey,直接报NSUnknowKeyException异常;

  • 如果没有setter方法,只有成员变量时,并且+ (BOOL)accessInstanceVariablesDirectly返回YES,KVO同样可以监测到属性值发生了改变;
    例如需要查找的属性叫age,则查找顺序如下

  1. _age
  2. _isAge
  3. age
  4. isAge

如果方法未找到,上面4个属性也未找到,则会报上面的异常setValue:forUndefineKey

KVC取值 valueForKey: 和valueForKeyPath:

  • 方法查找顺序
  1. getKey
  2. key
  3. isKey
  4. _key

如果方法未找到,则会调用系统方法+ (BOOL)accessInstanceVariablesDirectly判断是否可以直接访问成员变量,如果是NO,则会报valueForUndefineKey,如果是YES,则会按如下顺序查找成员变量:

  1. _key
  2. _isKey
  3. key
  4. isKey

你可能感兴趣的:(KVO和KVC)