美文网首页
ios--kvo的简单实用和原理总结

ios--kvo的简单实用和原理总结

作者: Harry__Li | 来源:发表于2020-09-07 14:53 被阅读0次
    1. kvo的应用场景
      当数据模型的数据发生改变时,视图组件能动态的更新,及时显示数据模型更新后的数据。通俗的来说就是,去监听某一属性,然后触发事件。
    2. kvo如何使用呢
      1. 首先需要注册
        [self.stutent addObserver:self forKeyPath:@"score" options:NSKeyValueObservingOptionNew context:NULL];
        observer 指观察者
        keyPath 表示被观察者的属性
        options 决定了提供给观察者change字典中的具体信息有哪些。
        context 它可以作为这个context的唯一标识,
        这段代码呢,就是观察者self当前类,观察stutent类score属性,发生改变。
        2.下来是监听的回调
     -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)objectchange:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if ([keyPath isEqualToString:@"score"]) {
    NSLog(@"当前的数值是:%ld",self.stutent.score);
        }
    }
    
    1. 移除监听
    -(void)dealloc{
        [self removeObserver:self forKeyPath:@"score"];
    }
    
    1. kvo的底层原理
      其实底层的原理也可以解释为什么在添加观察以后需要移除。
    NSKeyValueObservingOptions option = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
    
    NSLog(@"person1添加KVO监听对象之前-类对象 -%@", object_getClass(self.person1));
    NSLog(@"person1添加KVO监听之前-方法实现 -%p", [self.person1 methodForSelector:@selector(setAge:)]);
    NSLog(@"person1添加KVO监听之前-元类对象 -%@", object_getClass(object_getClass(self.person1)));
    
    [self.person1 addObserver:self forKeyPath:@"age" options:option context:@"age chage"];
    
    NSLog(@"person1添加KVO监听对象之后-类对象 -%@", object_getClass(self.person1));
    NSLog(@"person1添加KVO监听之后-方法实现 -%p", [self.person1 methodForSelector:@selector(setAge:)]);
    NSLog(@"person1添加KVO监听之后-元类对象 -%@", object_getClass(object_getClass(self.person1)));
    
    //打印结果
    KVO-test[1214:513029] person1添加KVO监听对象之前-类对象 -Person
    KVO-test[1214:513029] person1添加KVO监听之前-方法实现 -0x100411470
    KVO-test[1214:513029] person1添加KVO监听之前-元类对象 -Person
    
    KVO-test[1214:513029] person1添加KVO监听对象之后-类对象 -NSKVONotifying_Person
    KVO-test[1214:513029] person1添加KVO监听之后-方法实现 -0x10076c844
    KVO-test[1214:513029] person1添加KVO监听之后-元类对象 -NSKVONotifying_Person
    
    //通过地址查找方法
    (lldb) p (IMP)0x10f24b470
    (IMP) $0 = 0x000000010f24b470 (KVO-test`-[Person setAge:] at Person.h:15)
    (lldb) p (IMP)0x10f5a6844
    (IMP) $1 = 0x000000010f5a6844 (Foundation`_NSSetLongLongValueAndNotify)
    

    我们从上面的代码突然发现了一个东西NSKVONotifying_Person,这个是什么东西。为什么不是我们原有的person的类。
    这就是中间类。那为什么会有这个类呢?我是这么理解的。 观察观察,如果要你去观察一个东西,你是直接观察还是在背地里面观察效果好呢?当然是悄悄的观察更能看出东西,它可以更好的观察对象属性变化是不是。其实,kvo的原理也是类似的。
    过程呢很简单,就是我们要观察,person里面的age,然后在注册观察以后,isa指向了中间类NSKVONotifying_Person。

    1. NSKVONotifying_Person内部实现
     - (void)setAge:(int)age{
        _NSSet*ValueAndNotify();//这个方法调用顺序是什么,它是在调用何处方法,都在setter方法改变中详解
    }
    
    - (Class)class {
        return [LDPerson class];
    }
    
    - (void)dealloc {
        // 收尾工作
    }
    
    - (BOOL)_isKVOA {
        return YES;
    }
    

    只要注册了监听KeyPath,在中间类中肯定发现set方法。就像先在我们注册监听age的变化,而在中间类中就出现了setAge方法。当然,如果其他没有注册监听的属性,不会调用中间类的方法,还是继续使用原有类的方法。 dealloc这个其实不难理解,如果我每个类都有监听观察,不去释放销毁,那么这个东西会越积越多,是不是占用资源。 _isKVOA可以作为一个标记,可以这么说,这个方法标志这是不是生成的中间类。

    1. kvo和通知

    和 notification(通知)的区别?
    KVO 和 NSNotificationCenter 都是 iOS 中观察者模式的一种实现。区别在于,相对于被观察者和观察者之间的关系,KVO 是一对一的,而不是一对多的。KVO 对被监听对象无侵入性,不需要修改其内部代码即可实现监听。
    notification 的优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,例如键盘、前后台等系统通知的使用也更显灵活方便。

    相关文章

      网友评论

          本文标题:ios--kvo的简单实用和原理总结

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