Key-value observing provides a mechanism that allows objects to be notified of changes to specific properties of other objects. It is particularly useful for communication between model and controller layers in an application.

kvo提供了一种机制,允许其他方针的特定特点的改变告诉给方针。对于应用程序中模型层和操控层之间的通讯特别有用

这是苹果的官方文档描绘,咱们能够端倪出 MVVM的一些气味

信任没有不会使用的

KVO原理

咱们能够经过keypath做if 判别过滤

那么这个context是干嘛用的,怎样用?

让咱们回到官方文档

The context pointer in theaddObserver:forKeyPath:options:context:message contains arbitrary data that will be passed back to the observer in the corresponding change notifications. You may specifyNULLand rely entirely on the key path string to determine the origin of a change notification, but this approach may cause problems for an object whose superclass is also observing the same key path for different reasons.

context能够是恣意数据,能够用NULL,彻底依托path来确认告诉的来源,但这样会存在一个问题,便是父类也经过这个path来调查

一个很好的选择便是 用static变量指针作为context,这样基本上父类 子类都不会重复的,而彻底跳过了字符串的比较过滤,在解析告诉上更功率了

KVO原理

  • An observer does not automatically remove itself when deallocated. The observed object continues to send notifications, oblivious to the state of the observer. However, a change notification, like any other message, sent to a released object, triggers a memory access exception. You therefore ensure that observers remove themselves before disappearing from memory.

  • observer不会自动remove掉,被调查到方针在observer内存被收回之后,会持续向已开释的内存地址发送告诉,这是一件悲催的工作。因此你要保证observers在内存被收回之前执行remove

  • 所以,被调查方针 对 observer的持有是弱引证的,强引证的话,observer是无法开释的,就不存在 被调查方针 向 已开释的内存地址(observer被开释)发送告诉及消息 导致崩溃的产生, 但会呈现强引证 无法开释的问题

手动档 自动档

automaticallyNotifiesObserversOf….

KVO原理

KVO原理

关闭自动告诉,能够经过 willChange didChange 来手动发送告诉

组合调查

KVO原理

progress由 received 与 total 计算而来

KVO原理

可变数组的调查

发现,数组元素产生改变,并没有回调调查者监听办法

KVO原理

官方文档开始就预警了

为了理解KVO,必须先理解kvc

可变数组产生改变,并没有告诉调查者,咱们回到KVC文档查看

KVO原理

文档说的很清楚,创建一个可变content,再经过setValue:forKey: 存储回去

这种办法 苹果额外提供了一个技能 对于调集 持续遵照保持kvo

这样的话,那上面的问题就很简单解决了

KVO原理

KVO原理

change 字典里的kind 有 1 2

测验发现 当替换可变数组元素时,kind变为4

KVO原理

原理入门

KVO原理

这是官方文档上的一段描绘 大致意思

自动KVO 是经过 一个isa替换的技能完成的

当为一个方针注册observer时,它的isa就改变了,指向了一个中间类

所以你不能用isa来判别一个类,而应该经过 class办法来判别,原因便是你不知道你判其他方针是否被注册了调查者,而导致它的isa被修正,得到错误的成果

KVO原理猜想下 怎样完成

  • isa修正

  • 修正后的isa指向了一个新的类,这个类里必定做了一些事

    记得之前的AFNetworking一文,利用了OC dynamic特性,做了一个 URLSessionTask resume 替换,为了在 task resume时机增加必要告诉,然后持续康复为本来的resume

    这里应该也大差不差,在调用设置值 也便是 setXX 办法的时候,做一些告诉,然后再康复正常的setXX 办法调用

  • isa被修正后,官方文档也说了,调用class办法还能得到正确的类,那就也得利用swizzling

KVO原理

注册observer之后,经过 runtime api获取类,发现是其他类了

KVO原理

可是经过class获取,类却没有变

第一步猜想得证,动态生成了一个中间类 NSKVONotifying_IFLKVOObject,这咱们能够自己模仿去完成了

KVO原理

经过runtime api 打印 类及子类的一切类

发现被注册observer的类 此刻多了一个子类 NSKVONotifying_IFLKVOObject

而 NSKVONotifying_IFLKVOObject 打印类及子类 ,只有自己罢了

KVO原理

从打印成果看 发现办法没什么特其他,主要是setXX办法,class办法 dealloc

这个class办法 必定是为了 经过OC class获取到原本的类,与前面的猜想很接近,swizzle

KVO原理

移除调查者之后,类康复增加调查者之前的状态

可是假如remove observer 是经过 context remove掉的话,并没有彻底删去,类状态还无法康复,所以 remove的时候 直接经过keyPath删去就好了

之前的测验比如里,有一个细节我没提,便是 成员变量并不会告诉调查者,也便是并不调查成员变量

KVO原理

监听 被调查方针的name特点,经过堆栈信息 咱们看到经历了些什么操作

Foundation _NSSetObjectValueAndNotify

Foundation -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:]

Foundation -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:]

IFLArchitecture -[IFLKVOObject setName:](self=0x000060000380cf40, _cmd=”setName:”, name=@”(null)+1″)

自定义KVO完成

详细细节就不在文章里展开了,能够详细上 github 查看

不过需要留意两点

  • observer循环引证问题

  • observer可否自动销毁

KVO原理

KVO完成代码 github

iOS架构规划遗留了MVVM,有了KVC KVO的原理常识铺垫,那么接下来就能够议论MVVM了