美文网首页
iOS学习-KVO

iOS学习-KVO

作者: 快乐的tomato | 来源:发表于2020-06-06 10:15 被阅读0次
kvo

一、是个啥

KVO全称为Key Value Observing,键值监听,可以用于监听某个对象属性值的改变。
是观察者设计模式的一种实现。

二、用法

简单试用

#pragma mark - KVO

-(void)KVOTest{
    
    self.person = [[Person alloc] init];
    self.person.age = 10;

    //给person对象添加监听对象
    [self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"123"];

}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    self.person.age = 20;
}

//响应方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    //观察者观察name的变化,当点击屏幕,改变name的值,chang就会捕获新值
    
    NSLog(@"%@-%@-%@-%@",keyPath,object,change,context);
}

//移除监听
-(void)dealloc{
    
    [self.person removeObserver:self forKeyPath:@"age"];
}


三、KVO的底层是怎么实现的?

 self.xiaoming1 = [[XiaoMing alloc] init];
    self.xiaoming1.age = 1;
    
    self.xiaoming2 = [[XiaoMing alloc] init];
    self.xiaoming2.age = 2;
    
    [self.xiaoming1 addObserver:self //本控制器来监听
                       forKeyPath:@"age"//监听xiaoming1 age 的变化
                          options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld//通常选这2个,下面会解释
                          context:@""];//下面会演示
1、疑问

走的都是XiaoMing类方法setAge,为什么xiaoming1的age值,VC能监听到值的改变,xiaoming2不能?
这不是setAge的问题,是对象的问题
我们来打印一下这2个对象的isa,发现不一样


image.png
2、本质分析

未使用kvo监听的对象


请忽略图中的命名

使用kvo监听的对象


请忽略图中的命名.png

NSKVONotifying_XiaoMing是使用runtime动态创建的一个类,这就是OC强大的地方,可以在运行的过程中,自己创建一个类。
NSKVONotifying_XiaoMing是XiaoMing的子类。

3、本质验证

打印一下xiaoming1 、xiaoming2的类对象

 NSLog(@"🍎监听之前--xiaoming1的类对象:%@-xiaoming2的类对象:%@",object_getClass(self.xiaoming1),
                                                      object_getClass(self.xiaoming2));
    
 [self.xiaoming1 addObserver:self //本控制器来监听
                       forKeyPath:@"age"//监听xiaoming1 age 的变化
                          options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld//通常选这2个,下面会解释
                          context:@""];//下面会演示

  NSLog(@"🍎监听之后--xiaoming1的类对象:%@-xiaoming2的类对象:%@",object_getClass(self.xiaoming1),
    object_getClass(self.xiaoming2));
image.png

打印一下xiaoming1 、xiaoming2的setAge方法实现

 NSLog(@"🍎监听之前--方法实现:%p-%p",[self.xiaoming1 methodForSelector:@selector(setAge:)],
          [self.xiaoming2 methodForSelector:@selector(setAge:)]);
    
    [self.xiaoming1 addObserver:self //本控制器来监听
                       forKeyPath:@"age"//监听xiaoming1 age 的变化
                          options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld//通常选这2个,下面会解释
                          context:@""];//下面会演示
NSLog(@"🍎监听之后--方法实现:%p-%p",[self.xiaoming1 methodForSelector:@selector(setAge:)],
    [self.xiaoming2 methodForSelector:@selector(setAge:)]);
image.png

再来看一下方法实现


image.png

打印一下类对象和元类对象

NSLog(@"🍎xiaoming1:类对象-%@,元类对象-%@",object_getClass(self.xiaoming1),object_getClass(object_getClass(self.xiaoming1)));
     NSLog(@"🍎xiaoming2:类对象-%@,元类对象-%@",object_getClass(self.xiaoming2),object_getClass(object_getClass(self.xiaoming2)));
image.png
4、Foundation里的_NSSetValueAndNotify的实现

如果会点逆向的知识可能会好探索一些,这里直接说结论

打印调用顺序

-(void)setAge:(int)age{
    
    _age = age;
    NSLog(@"setAge");
}

-(void)willChangeValueForKey:(NSString *)key{
    
    [super willChangeValueForKey:key];//为了干扰以前的实现,调用super
    NSLog(@"willChangeValueForKey");
}

-(void)didChangeValueForKey:(NSString *)key{
    
    NSLog(@"didChangeValueForKey-开始");
    [super didChangeValueForKey:key];
    NSLog(@"didChangeValueForKey-结束");
}
image.png

四、问题

1、iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)

1、使用runtime API动态生产一个子类,并且让实例对象的isa指向这个全新的
子类
2、当修改对象的属性时,会调用Foundation里的_NSSetXXXXAndNotify的函数

  • willChangeValueForKey
  • 父类原来的setter
  • didChangeValueForKey
  • 内部会触发监听器observe的监听方法:observeValueForKeyPath

2、如何手动触发KVO?

这个题的理解应该是不改变对象的属性值,也能触发KVO

手动调用willChangeValueForKey和didChangeValueForKey方法。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    [self.xiaoming1 willChangeValueForKey:@"age"];
    [self.xiaoming1 didChangeValueForKey:@"age"];
}
image.png

3、直接修改成员变量会不会触发KVO?
不会

4、KVO的运用场景?

相关文章

  • iOS-KVO(二) 使用注意点

    iOS-KVO(一) 基本操作iOS-KVO(二) 使用注意点iOS-KVO(三) 窥探底层实现iOS-KVO(四...

  • iOS-KVO(三) 窥探底层实现

    iOS-KVO(一) 基本操作iOS-KVO(二) 使用注意点iOS-KVO(三) 窥探底层实现iOS-KVO(四...

  • iOS-KVO(四) 自定义KVO+Block

    iOS-KVO(一) 基本操作iOS-KVO(二) 使用注意点iOS-KVO(三) 窥探底层实现iOS-KVO(四...

  • iOS-KVO(一) 基本操作

    iOS-KVO(一) 基本操作iOS-KVO(二) 使用注意点iOS-KVO(三) 窥探底层实现iOS-KVO(四...

  • iOS - KVO

    [toc] 参考 KVO KVC 【 iOS--KVO的实现原理与具体应用 】 【 IOS-详解KVO底层实现 】...

  • KVO学习笔记

    1.KVO初探学习2.KVO 底层原理探索 1.KVO初探学习 移除观察者的重要性 (IOS11之后说不移除是不对...

  • Objective-C的本质(4)—— KVO本质

    参考:iOS底层原理总结 - 探寻KVO本质iOS-KVO本质 问题一:kvo如果找到对应的属性 KVO不存在查找...

  • 深入理解KVO

    iOS | KVO | Objective-C KVO的本质是什么,如何手动触发KVO? 1.什么是KVO KVO...

  • iOS学习-KVO

    一、what KVO全称为Key Value Observing,键值监听。可以用于监听某个对象属性值的改变 二、...

  • iOS 关于KVO的一些总结

    本文参考链接: iOS KVO详解 Foundation: NSKeyValueObserving(KVO) KV...

网友评论

      本文标题:iOS学习-KVO

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