KVO的本质

1.生成子类
系统会通过runtime动态生成一个名为NSKVONotifying_xxx(被监听类名)继承自被监听类的子类
例如 YHObject  -> NSKVONotifying_YHObject
调用方法 objc_allocateClassPair([YHObject class], "YHObject", 0);
 
 @interface YHObject : NSObject
 
 @property (nonatomic, assign) int age;
 
 @end
 
 @implementation YHObject
 
 @end
 
 
 @interface NSKVONotifying_YHObject : YHObject
 
 @end
 
 @implementation NSKVONotifying_YHObject
 
 - (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];
 }
 
 // 屏幕内部实现,隐藏了NSKVONotifying_MJPerson类的存在
 - (Class)class
 {
     return [YHObject class];
 }
 
 - (void)dealloc
 {
 // 收尾工作
 }
 
 - (BOOL)_isKVOA
 {
 return YES;
 }

 @end
2.重写父类的set方法
  子类重写被监听属性的set方法,在set方法里面调用  _NSSetIntValueAndNotify();
  
  _NSSetIntValueAndNotify的大概实现是这样的
  [self willChangeValueForKey:@"age"];  // 将会改变
  [super setAge:age];                   // 调用父类的set方法给成员变量赋值
  [self didChangeValueForKey:@"age"];   // 改变

  didChangeValueForKey
  通知监听器某某属性发生了改变既调用公共的方法
  [oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
3子类重写class方法
// 返回原来的类来迷惑开发者,隐藏实现原理
  - (Class)class
  {
      return [YHObject class];
  }
4.总结
KVO观察对象的特定属性发生变化的核心思想是利用isa-swizzling.
被观察的特定属性所属的对象的isa会指向一个动态生成的中间类,并且中间类拥有一个统一的前缀NSKVONotifying_,中间类继承于对象的父类。
中间子类会重写3个方法 : setter、class、dealloc,另外会自带一个判断是否是KVO生成的子类的方法 : _isKVOA。
当移除观察的时候,被观察的属性所属的对象的isa会重新指会原本的类。
生成的中间子类不会被销毁,依然存在于原来类的缓存之中。

你可能感兴趣的:(KVO的本质)