oc 基础 - KVO

107 阅读2分钟

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

监听的原理是从写set方法 更换 所以 能否监听 是需要判断 有没有 set方法

为什么新生成的类没有get方法 , 因为 父类有了,不需要重写和这个无意义

利用runtime 动态生成子类 并且让 isa 指向全新的子类 , 当修改实例对象的属性时 会调用 foundation 的_NSSet*ValueForKeyNotify (will super did) did 方法 会出发 监听方法 observeValuefoKeyath:

2. 如何手动触发KVO

[self.person willCHangeForkey@age"]; [self person didchangevalueforKey:@"age"];

didchange 内部会判断willchange 是否被调用了, 所以需要先调用 willchangeg方法

  1. 直接修改成员变量会出发KVO 吗 ?

{ int _age; }

self.person.age = 2: 会调动 self.person ->age = 2, 不会调

不会, 因为没有调用set方法

kvo key-value observing 键值监听

// 添加监听 NSKeyvalueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld

[self.person addObserviing:self forKeyPath:@"age" options:options context:@"sd"]; // 移除监听

  • (void)dealloc { [self.person removeObser:self forKeyPath:@"age"]; }

// 值改变的时候回调用

  • (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(id) change context:(void *)context { nslog( @"%@",newValue); }

  • (void)changeValue {

    self.person1.age = 21; self.perdon2.age = 22;

}

  • (void)setAge:(nsintering) age{ _age = age; }

两个set 方法都执行了但是只有person1 会 调用监听方法

查看流程 首先查看 isa指针

lldb p self.person1.isa (Class) $0 = NSKVONotifying_Person 使用KVO 监听 isa 指针变了 Fix-it applied, fixed expression was : self.person1.isa

lldb p self,person2.isa (Class) $1 = Person // 未使用KVO 监听 isa 指针不变

NSKVONotifying_Person Class 是 runtime 运行中动态创建的类, 是person 的子类 , 他的superClass 指向了 person

全新的这个类中 的类对象 重写了 四个方法 , setAge: class deallock _isKVOA

派生类的setAge: 方法会拦截 方法的查找 ,

person 调用 setAge: 会调用Foundation 框架中的_NSSetIntValueAndNotify

类似这样

@implementation NSKVONotifying_Person

  • (void)setAge:(int)age {

    _NSSetIntValueAndNotify();

}

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

  • (void)didChangeValueForKey:(Nssting *)key { // 通知监听器 属性发生改变 self observeValueForkeyPath:()path ofObject:()object change:()cange content:()content

}

  • (Class)class {

    return seuper Classs }

  • (void)delloc {

}

  • (Bool)_isKVOA { }

@end

[ person1 class]; [person2 class];

NSlog(objc_getClass(person1))

NSKVONotifying_Person

NSlog(person class)

Person

使用runtime 获取类和 preson class 不一样, runtime 获取的是真的类

class 方法 是获取从写的 Class 方法 获取 苹果不想暴露真实类型 屏蔽内部实现 隐藏了类的实现

  • (void)printMethodNamesOfClass:(Class)cls {

}

关于动态生成子类

objc_allocateClassPair and before objc_regsterClassPair