iOS开发资料收集区ios乔帮主的遗产

探究KVO的底层实现原理

2016-04-11  本文已影响10213人  Mg明明就是你

addObserver:forKeyPath:options:context:各个参数的作用分别是什么, observer中需要实现哪个方法才能获得KVO回调?

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

一、KVO (Key-Value Observing)

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

有意思的是,你不需要给被观察的对象添加任何额外代码,就能使用 KVO 。这是怎么做到的?

二、 KVO内部实现原理


三、如何手动触发一个value的KVO

@property (nonatomic, strong) NSDate *now;

- (void)viewDidLoad
{
    [super viewDidLoad];

    // “手动触发self.now的KVO”,必写。
    [self willChangeValueForKey:@"now"];

    // “手动触发self.now的KVO”,必写。
    [self didChangeValueForKey:@"now"];
}
手动触发一个value的KVO.png

四、补充: 如何关闭默认的KVO的默认实现,并进入自定义的KVO实现?(看链接)


五、附注: KVC底层实现原理(如下)

KVC运用了一个isa-swizzling技术. isa-swizzling就是类型混合指针机制, 将2个对象的isa指针互相调换, 就是俗称的黑魔法.
KVC主要通过isa-swizzling, 来实现其内部查找定位的. 默认的实现方法�由NSOject提供isa指针, 如其名称所指,(就是is a kind of的意思), 指向分发表对象的类. 该分发表实际上包含了指向实现类中的方法的指针, 和其它数据。

  • 具体主要分为三大步
  • 或者这么说

比如说如下的一行KVC的代码:

[object setValue:@"13123" forKey:@"uuid"];

就会被编译器处理成:
// 首先找到对应sel
SEL sel = sel_get_ uuid("setValue:forKey:");
// 根据object->isa找到sel对应的IMP实现指针
IMP method = objc_msg_lookup (object->isa,sel);
// 调用指针完成KVC赋值
method(object, sel, @"13123", @"uuid");

可供参考文章

上一篇下一篇

猜你喜欢

热点阅读