KVO总结

KVO的全称是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变

KVO总结_第1张图片
image.png

查看被监听对象的isa

(lldb) p self.person1.isa
(Class) $0 = NSKVONotifying_LQPerson
  Fix-it applied, fixed expression was: 
    self.person1->isa
(lldb) p self.person1->isa
(Class) $1 = NSKVONotifying_LQPerson

** 查看对象添加监听前后的方法**

NSLog(@"person1添加KVO监听之后 %p", [self.person1 methodForSelector:@selector(setAge:)]

(lldb) p (IMP)0x109e3b570
(IMP) $1 = 0x0000000109e3b570 (Interview01`-[LQPerson setAge:] at LQPerson.m:13)
(lldb) p (IMP) 0x10a1e2f8e
(IMP) $2 = 0x000000010a1e2f8e (Foundation`_NSSetIntValueAndNotify)

通过获取对象的类对象和元类对象打印可知,两个地址完全不同,意味着,runtime生成的这个类对象的元类是它自己的元类对象,而不是之前对象的元类

我们可以通过runtime查看新的类有哪些方法
为什么没有重写get方法?因为父类已经有了

_NSSetValueAndNotify的内部实现*

KVO总结_第2张图片
image.png

  1. 调用willChangeValueForKey:
  2. 调用原来的setter实现
  3. 调用didChangeValueForKey:
    didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法

伪代码

- (void)setAge:(int)age
{
    _NSSetIntValueAndNotify();
}

//伪代码
void _NSSetIntValueAndNotify()
{
    [self willChangeValueForKey:@"age"];
    [super setAge:age];
    [self didChangeValueForKey:@"age"];
}

- (void)didChangeValueForKey:(NSString *)key
{
    //通知监听器
    [oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}

QA

  • iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)
    利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类
    当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数
    willChangeValueForKey:
    父类原来的setter
    didChangeValueForKey:
    内部会触发监听器(Oberser)的监听方法( observeValueForKeyPath:ofObject:change:context:)

  • 如何手动触发KVO?
    手动调用willChangeValueForKey:和didChangeValueForKey:

  • 直接修改成员变量会触发KVO么?
    不会触发KVO

你可能感兴趣的:(KVO总结)