美文网首页swift 基础
iOS开发面试-八个考点, 带你全面掌握KVO&KVC

iOS开发面试-八个考点, 带你全面掌握KVO&KVC

作者: iOS丶lant | 来源:发表于2022-04-25 13:46 被阅读0次

原文地址

1. KVO的实现原理

  • 通过runtime派生子类的方式复写相关需要KVO监听的属性, 在该属性setter之前和之后调用NSObject的监听方法, 这样KVO就实现了属性变换前后的回调.
  • KVO派生的子类具体格式应该是:NSKVONotifying_+类名的类, 如NSKVONotifying_Person
  • 未使用KVO监听的对象的isa指针结构图
  • 使用了KVO监听的对象的isa指针结构图
  • _NSSetValueAndNotify的内部实现
  • 子类的内部方法
  • class方法屏蔽了内部实现, 隐藏了NSKVONotifying_MJPerson类的存在, runtime可以拿到真实的类型

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.
  • 取值方法valueForKey:的原理
  1. 首先会按照顺序一次查找getKey:、key、isKey、_key:这四个方法, 只要找到这四个方法当中的任何一个就直接调用该方法;
  2. 如果没有找到, 那么这个时候会查看accessInstanceVariablesDirectly方法的返回值, 如果返回的是NO(不允许直接访问成员变量), 那么会调用valueforUndefineKey:方法, 并抛出异常NSUnknownKeyException;
  3. 如果accessInstanceVariablesDirectly方法返回的是YES, 也就是说可以访问其成员变量, 那么就会按照顺序一次查找_key、_isKey、key、isKey这四个成员变量, 如果找到了, 就直接取值; 如果依然没有找到成员变量, 那么会调用valueforUndefineKey方法, 并抛出异常NSUnknownKeyException.

7. KVC的使用

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

8. KVO的优缺点

8.1 KVO的优点:

  1. 能够提供一种简单的方法实现两个对象间的同步.如ModelView之间同步.
  2. 能够对内部对象(非我们创建的对象)的状态改变做出响应, 而不需要改变内部对象的实现.
  3. 能够提供所观察属性的最新值和之前的旧值.
  4. 通过addObserver: forKeyPath来观察属性, 因此可以观察嵌套对象.

8.2 KVO的缺点

  1. 我们观察的属性必须使用String来定义. 编译时, 编译器不会发出警告及检查.
  2. 对属性的重构会导致我们的观察代码不再可用.
  3. 所有的观察代码通过一个方法来做, 会生成复杂的if语句.
  4. 被观察者释放时, 不需要移除观察者, 会造成闪退.

同时我也整理了一些面试题,有需要的朋友可以加QQ群:1012951431 获取

相关文章

网友评论

    本文标题:iOS开发面试-八个考点, 带你全面掌握KVO&KVC

    本文链接:https://www.haomeiwen.com/subject/aocnertx.html