1. KVO的完成原理

  • 经过runtime派生子类的办法复写相关需求KVO监听的特点, 在该特点setter之前和之后调用NSObject的监听办法, 这样KVO就完成了特点变换前后的回调.
  • KVO派生的子类详细格局应该是:NSKVONotifying_+类名的类, 如NSKVONotifying_Person
  • 未运用KVO监听的目标的isa指针结构图

七个考点, 带你全面掌握KVO&KVC

  • 运用了KVO监听的目标的isa指针结构图

七个考点, 带你全面掌握KVO&KVC

七个考点, 带你全面掌握KVO&KVC

  • _NSSetValueAndNotify的内部完成
    七个考点, 带你全面掌握KVO&KVC

七个考点, 带你全面掌握KVO&KVC

  • 子类的内部办法
  • class办法屏蔽了内部完成, 躲藏了NSKVONotifying_MJPerson类的存在, runtime能够拿到实在的类型
    七个考点, 带你全面掌握KVO&KVC

七个考点, 带你全面掌握KVO&KVC

2. 怎么手动触发一个KVO

  • 键值调查通知依赖于NSObject的两个办法
    • willChangeValueForKey:
    • didChangeValueForKey:
  • 在一个被调查特点产生改动之前, willChangeValueForKey:一定会被调用, 这就会记载旧的值.
  • 当改动产生后, didChangeValueForKey:会被调用, 继而observeValueForKey:ofObject:change:context也会被调用.
  • 假如能够手动完成这些调用, 就能够完成”手动触发KVO”了.

3. 怎么给体系KVO设置筛选条件?

  • 如:取消Personage特点的默认KVO, 设置age大于18时, 手动触发KVO
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
    if ([key isEqualToString:@"age"]) {
        return NO;
    }
    return [super automaticallyNotifiesObserversForKey:key];
}
- (void)setAge:(NSInteger)age {
    if (age >= 18) {
        [self willChangeValueForKey:@"age"];
        _age = age;
        [self didChangeValueForKey:@"age"];
    } else {
        _age = age;
    }
}

4. 经过KVC修正特点会触发KVO吗?

  • 会触发KVO, 即使没有声明特点, 只需成员变量, 只需accessInstanceVariablesDirectly回来的是YES, 允许拜访其成员变量,
  • 那么不论有没有调用setter办法, 经过KVC修正成员变量的值, 都会触发KVO.
  • 这也说明经过KVC内部完成了willChangeValueForKey:办法和didChangeValueForKey:办法.

5. 直接修正成员变量会触发KVO吗?

  • 不会触发KVO, 直接修正成员变量内部并没有做处理仅仅单纯的赋值, 所以不会触发KVO.

6. KVC的底层完成是什么?

  • 赋值办法setValue:forKey:的原理
  1. 首先会依照次序一次查找setKey:办法和_setKey:办法, 只需找到这两个办法当中的任何一个就直接传递参数, 调用办法;
  2. 假如没有找到setKey:_setKey:办法, 那么这个时分会检查accessInstanceVariablesDirectly办法的回来值, 假如回来NO(也就是不允许直接拜访成员变量), 那么会调用setValue:forUndefineKey:办法, 并抛出反常NSUnknownKeyException;
  3. 假如accessInstanceVariablesDirectly办法回来的是YES, 也就是说能够拜访其成员变量, 那么就会依照次序一次查找_key、_isKey、key、isKey这四个成员变量, 假如查找到了, 就直接赋值; 假如依然没有查到, 那么会调用setValue:forUndefineKey:办法, 并抛出反常NSUnknownKeyException.

七个考点, 带你全面掌握KVO&KVC

  • 取值办法valueForKey:的原理
  1. 首先会依照次序一次查找getKey:、key、isKey、_key:这四个办法, 只需找到这四个办法当中的任何一个就直接调用该办法;
  2. 假如没有找到, 那么这个时分会检查accessInstanceVariablesDirectly办法的回来值, 假如回来的是NO(不允许直接拜访成员变量), 那么会调用valueforUndefineKey:办法, 并抛出反常NSUnknownKeyException;
  3. 假如accessInstanceVariablesDirectly办法回来的是YES, 也就是说能够拜访其成员变量, 那么就会依照次序一次查找_key、_isKey、key、isKey这四个成员变量, 假如找到了, 就直接取值; 假如依然没有找到成员变量, 那么会调用valueforUndefineKey办法, 并抛出反常NSUnknownKeyException.

七个考点, 带你全面掌握KVO&KVC

7. KVC的运用

  • 动态地取值和设置值
  • 拜访和修正私有变量
    • 修正一些控件的内部特点
    • 如之前的UITextFieldplaceHolderText.
  • 模型和字典的转换

8. KVO的优缺陷

8.1 KVO的优点:

  1. 能够供给一种简略的办法完成两个目标间的同步.如ModelView之间同步.
  2. 能够对内部目标(非咱们创立的目标)的状态改动做出呼应, 而不需求改动内部目标的完成.
  3. 能够供给所调查特点的最新值和之前的旧值.
  4. 经过addObserver: forKeyPath来调查特点, 因此能够调查嵌套目标.

8.2 KVO的缺陷

  1. 咱们调查的特点有必要运用String来定义. 编译时, 编译器不会发出警告及检查.
  2. 对特点的重构会导致咱们的调查代码不再可用.
  3. 一切的调查代码经过一个办法来做, 会生成杂乱的if语句.
  4. 被调查者开释时, 不需求移除调查者, 会形成闪退.