kvo和kvc的底层实现

kvo是个啥

KVO 是 Objective-C 对观察者模式(Observer Pattern)的实现。也是 Cocoa Binding 的基础。当被观察对象的某个属性发生更改时,观察者对象会获得通知。

kvo的API

/**
 1. self.user:要监听的对象
 2. 参数说明:
    * @param addObserver  观察者,负责处理监听事件的对象
    * @param forKeyPath 要监听的属性
    * @param  options 观察的选项(观察新、旧值,也可以都观察)
    * @param context 上下文,用于传递数据,可以利用上下文区分不同的监听
 */
[self.user addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"User Name"];

/**
 *  当监控的某个属性的值改变了就会调用
 *
 *  @param keyPath 监听的属性名
 *  @param object  属性所属的对象
 *  @param change  属性的修改情况(属性原来的值`oldValue`、属性最新的值`newValue`)
 *  @param context 传递的上下文数据,与监听的时候传递的一致,可以利用上下文区分不同的监听
 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    NSLog(@"%@对象的%@属性改变了:%@", object, keyPath, change);
}

cocoa为kvo都做了些什么.

  1. kvo的实现是在runtime期间做的
  2. 当一个类第一次被观察的时候,例如类User, runtime会重写User的派生类NSKVONotifying_User, 派生类被重写的方法主要是其被监听值的set方法,例如:
  • 监听前
- (void)setNow:(NSDate *)date {
    [super setValue: date forKey:@"now"];
}
  • 监听后
- (void)setNow:(NSDate *)date {
    [self willChangeValueForKey:@"now"];
    [super setValue: date forKey:@"now"];
    [self didChangeValueForKey:@"now"];
}
  1. 重写class方法,隐藏派生类 'NSKVONotifying_User'

从人家那盗了个图,展示kvo重写的过程:


kvo重写示意图

kvc是个啥

全称是Key-value coding,翻译成键值编码。顾名思义,在某种程度上跟map的关系匪浅。它提供了一种使用字符串而不是访问器方法去访问一个对象实例变量的机制。

kvc的api

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

kvc做了什么

当调用kvc的api的时候, 实际上会进行如下操作:

  1. 先查找变量对应的set和get方法
  2. 如果第一步没有查找到,则查找_set和_get方法
  3. 如果第二部没有查找到,则直接查找变量key或_key
  4. 如果仍未找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。

你可能感兴趣的:(kvo和kvc的底层实现)