KVO相关问题收集

561 阅读2分钟

最近准备面试,总结了一些KVO的问题,答案基本都可以从下边几篇博客找到。

1.什么是KVO?

Key-Value Observer,允许对象监听其他对象的属性的改变,并且在改变时触发相应的事件。一般继承自NSObject的对象都默认支持KVO。

2.基本使用:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    // Do any additional setup after loading the view.
    //keypath:对应的属性。
    //NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld 会把旧值和新值都返回给你,
    NSKeyValueObservingOptionInitial会在注册完立马调用一次。
    context:可以在接收回调时接收到任意类型的值。
    self.per = [Person new];
    [self.per addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"zmodo"];
}

- (void)viewDidAppear:(BOOL)animated{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self setValue:@"kvo" forKeyPath:@"per.name"];
    });
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"keypath:%@-object:%@-change:%@-context:%@",keyPath,object,change,context);
    keypath:name-object:<Person: 0x6000029fc570>-change:{
    kind = 1;
    new = kvo;
    old = "<null>";
}-context:zmodo

}

<1>添加观察者,并不会强引用

<2>移除观察者,一般添加和移除要成对出现,要不然容易crash。

3.什么时候触发KVO?

调用属性的setter方法,使用kvc设置属性值时都会触发

4.如何手动触发?

调用[self willChangeValueForKey:@"balance"]和didChangeValueForKey都会触发KVO。

5.如何禁用KVO?

在+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey方法中单独设置就可以了。

6.设置私有变量的值会触发kvo吗? 会

7.KVO的实现原理是怎么样的?

KVO的实现主要依赖于runtime。对于被观察的类,系统会动态的给他生成一个名字为Knofiy_Class的中间类,它是原来类的子类,并且让对象的isa指针指向它,然后重写这个类里对应属性的setter方法。值修改前会调用willChangeValueForKey方法,修改后会调用didChangeValueForKey。

8.KVO的缺点有哪些?

属性名修改后keypath忘记修改很容易导致这样的NSUnknownKeyException 的crash。

语法比较分散。

9.碰到的问题?

<1>.父类中也观察了某个属性,子类中也有,子类把父类的覆盖掉。

在子类中调用父类的方法,并且在父类和子类中都加入相关的判断,需要注意:父类的属性改变时,收到通知时,收到的object也是子类对象。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    if (object == self && [keyPath isEqualToString:@"person"]) {
        NSLog(@"CHildkeypath:%@-object:%@-change:%@-context:%@",keyPath,object,change,context);

    }else{
//        NSLog(@"keypath:%@-object:%@-change:%@-context:%@",keyPath,object,change,context);

    }
    
    
}

<2>多次removeobserver会crash 如何解决。 www.jianshu.com/p/e68b48f0c…

<3>.多次add会多次收到通知吗? 会

<4>.属性改变了,keypath忘记修改,如何解决。

9.推荐一个Facebook开源的框架KVOController

如果面试时能把实现原理讲一下就更好了。

参考链接: www.jianshu.com/p/badf5cac0… tech.glowing.com/cn/implemen… www.jianshu.com/p/badf5cac0…