面经日常小知识点iOS开发你需要知道的

解剖iOS中KVO的原理

2018-06-12  本文已影响422人  roger_Hunter

        为什么还要讲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详解中解答

上一篇下一篇

猜你喜欢

热点阅读