KVO与KVC

KVO

  • 定义:
    Key-Value Observing 即键值监听,用于监听某个对象属性值的变化

  • 本质:
    1> 利用运行时动态生成一个子类,并让实例对象的isa指针指向这个子类
    2> 当设置instance对象的属性时,会调用Foundation的_NSSet{XXX}ValueAndNotify函数,该函数内部实现如下:
    a)调用willChangeValueForKey:
    b)调用父类原来的setter
    c)调用didChangeValueForKey:(didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法)

  • 运行时生成的中间类NSKVONotifying_{ClassName}的内部组成
    isa
    superclass
    setAge: (IMP指向_NSSet{XXX}ValueAndNotify的实现)
    class
    dealloc
    _isKVOA

如何得知添加KVO的instance对象的isa指针指向的不是原有的类对象

  • 在添加KVO之前和之后分别打印instance对象的isa指针
NSLog(@"person添加kvo之前 - %@", object_getClass(self.person)); /// Person
[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
NSLog(@"添加kvo之后 - %@", object_getClass(self.person)); /// NSKVONotifying_Person

添加了KVO的instance对象和未添加KVO的对象同是调用属性的set方法,为什么添加KVO的可以触发 observeValueForKeyPath:ofObject:change:context:方法

  • 猜想,是不是运行时生成的子类中的set方法实现不一样,代码如下
NSLog(@"person添加kvo之前 - %p", [self.person methodForSelector:@selector(setAge:)]); /// 0x10e3a0250
[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
NSLog(@"person添加kvo之后 - %p", [self.person methodForSelector:@selector(setAge:)]); /// 0x10e7509e4
  • 由上边的打印发现,set方法的IMP在添加KVO前后有变化
  • 断点,在控制台输入命令 p (IMP)0x1084e19e4 ,得到如下信息,可知添加了KVO后,调用属性的set方法,会自动触发Foundation的_NSSetIntValueAndNotify方法,而_NSSetIntValueAndNotify方法内部实现了如下操作
    a)调用willChangeValueForKey:
    b)调用父类原来的setter
    c)调用didChangeValueForKey:(didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法)
(IMP) $1 = 0x00000001084e19e4 (Foundation`_NSSetIntValueAndNotify)

如何手动触发KVO

手动调用willChangeValueForKey:didChangeValueForKey:方法

KVC

  • 定义:
    Key-Value Coding,即键值编码,可以通过某个key来访问属性

  • 常见API;
    -(void)setValue:(id)value forKeyPath:(NSString *)keyPath;
    -(void)setValue:(id)value forKey:(NSString *)key;
    -(id)valueForKeyPath:(NSString *)keyPath;
    -(id)valueForKey:(NSString *)key;

  • setValue:forKey:的原理


    setValue的原理.png
  • valueForKey:的原理


    valueForKey的原理.png

使用KVC为属性设置值会触发KVO

你可能感兴趣的:(KVO与KVC)