解剖iOS中KVO的原理

        为什么还要讲KVO的原理呢,如果想了解KVO原理,上网一查,可以搜出一大堆文章,不是更好?以前我也是上网一查,大概知道了怎么回事,但是呢,过一段时间,你肯定忘了,不知道你是否有同感,原因?

1.  你用零碎的时间学习零碎的知识,不能形成有意识的系统知识,这样只是一场过客,时间一长,你还得去重新查找,浪费时间和精力不说,你觉的有意思吗?

2. 网上的文章说的不全,比如说,说了对象,但是没有说容器;说了基本使用,没有说底层的实现等

3. 没有相关代码来佐证等

        而本篇文章试图从最简单的用法说起,由浅入深,覆盖对象和容器,底层机制

一.    一般基本的使用,新建一个对象Animal,在头文件中加一个name的属性


图1

同时在ViewControler中创建Animal的对象,同时监听该对象的name属性


图2

结果:点击vc,得到结果如下:


图3

这是一个对象完整的使用基本KVO的流程

说明:

        NSKeyValueObservingOptionNew              // 返回新值

        NSKeyValueObservingOptionOld                // 返回旧值

        NSKeyValueObservingOptionInitial             // 注册的时候就会发一次通知,改变的时候也会发通知

        NSKeyValueObservingOptionPrior             // 改变之前发一次,改变之后发一次

二. 上面是name改变值都会发送通知,但是现在我只要满足特定条件才发送通知,另外情况都不需要发送通知,怎么做呢?

    iOS提供了2种模式给我们选择,一种是 默认的自动模式,一种是手动模式

    2.1 手动模式

          在Animal的m文件中重载实现automaticallyNotifiesOberversOfName函数,返回NO即可,结果是没有返回值

图4

        然后我想要只在touchesBegan函数中才改变值才通知,另外情况都不需要通知,如下


图5

        为什么需要willChange和didChange 2个函数呢?因为NSKeyValueObservingOptions的选项有返回旧值和新值,所以willChange对应返回旧值,didChange返回新值,也就是说这2个是成双成对出现的

三. 属性依赖,如果在Animal对象里有另外一个对象,然后要监听那个对象的属性呢,新增一个cat对象,增加age的属性,在Animal里增加一个Cat对象,同时在ViewController里监听Cat对象的age属性


图5

另外一种情况是:如果在cat对象中有很多属性,这样在监听的时候是不是要写很多监听的代码呢,是否有简单的方法来统一监听所有的属性呢??

eg:

    [self.a addObserver:self forKeyPath:@"cat.age" options:NSKeyValueObservingOptionNew context:nil];

    [self.a addObserver:self forKeyPath:@"cat.kind" options:NSKeyValueObservingOptionNew context:nil];

    ....

iOS提供了一个方法来返回指定的属性容器,达到只要监听对象的目的

eg: 在ViewController中

[self.a addObserver:self forKeyPath:@"cat" options:NSKeyValueObservingOptionNew context:nil];

相应的在Animal的m文件中重载keyPathsForValuesAffectingValueForKey函数


四. 如果我要观察的是容器呢,比如NSMutableArray呢,我在Animal头文件中增加一个NSMutableArray的属性,在ViewController中进行addObject操作


图6


图7

运行发现,像array里增加值,并不能发送通知,为什么??

结论:KVO监听的是属性的set方法,不是对象的变量,而addObject方法明显不是set方法,所以不会触发通知

如果NSMutableArray的addObject方法还不能证明的话,那么再通过一个例子来证明

在Animal头文件中声明一个name的变量


图8

在ViewController中监听name属性


图9

运行后发现,没有发送通知

五. 底层实现

    5.1 当调用addObserver函数的时候,系统运行时自动帮你把Animal类替换为了 NSKVONotifying_Animal类,同时重写了set方法,当我们查看addObserver函数的时候,可以看到该函数在NSObject分类下@interfaceNSObject(NSKeyValueObserverRegistration)

这里大家要理清一个概念:方法跟类有关系,成员变量跟对象有关系

   5.2 新增一个NSObject的一个分类来替换系统的分类


图10

疑问:为什么要添加setName方法?自定义的子类没有该方法?是的,没有该方法,子类继承于父类,父类有,但是子类没有

六. 容器实现监听,使用KVC技术

iOS提供了mutableArrayValueForKey等多个KVC的方法来生成一个KVO的array,来实现addObject方法的监听

但是,我发现count不是数组的属性,不能进行监听修改,以上就是本文的内容,有不当之处欢迎指出。

七. 课后作业

      7.1 不知道大家有没发现,对于change返回的kind值,对象和容器是不一样的,一个是1,一个是2,那么是否还有第三个,第四个... 呢,这个kind代表什么意思呢?


对象


容器

    7.2. 关于在图10中的keyMethod方法,里面分别去调用父类的setName,同时调用observer函数,为什么不直接调用子类的setName方法??

关于这些问题,我会在下期的KVC详解中解答

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,764评论 8 265
  • 问题 iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?) 如何手动触发KVO ? 首先需要了解KVO...
    hjltony阅读 595评论 0 2
  • KVC KVC定义 KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过K...
    暮年古稀ZC阅读 2,207评论 2 9
  • 该文章属于刘小壮原创,转载请注明:刘小壮[https://www.jianshu.com/u/2de707c93d...
    刘小壮阅读 48,709评论 35 227
  • 昨晚读书会很晚才结束,和男人商量着今天去扫墓的。 今早一早就醒来,做饭喊男人吃饭,男人很沉默。我也不去编织,做...
    张连娜阅读 214评论 1 1