学习MJ的视频课程,整理并记录知识点–KVC的本质
[TOC]
KVC的全称是Key-Value Coding
,俗称“键值编码”,可以通过一个key来访问某个属性
常见的API有
1 | - (void)setValue:(id)value forKeyPath:(NSString *)keyPath; |
基本使用
设值
1、我们可以通过-setValue:forKey:
,或者-setValue:forKeyPath:
给对象的属性赋值,也可以直接调用对象的属性赋值,如下三个方法的效果等价。
1 | person.age = 10; |
-setValue:forKey:
、-setValue:forKeyPath:
这两个方法的调用结果一样,函数名很相似,它们两个的区别是什么?
我们先看它的API文档
Discussion
The default implementation of this method gets the destination object for each relationship using valueForKey:, and sends the final object a setValue:forKey: message.
可以概述如下:-setValue:forKeyPath:
支持路径方式的参数([person setValue:@10 forKeyPath:@"cat.weight"];
),
它会新利用路径查找到指定的层级,内部最终是会调用-setValue:forKey:
2、KVC的另一种使用场景就是我么利用它进行对象的私有属性赋值。
1 | [searchField setValue:[UIColor whiteColor] forKeyPath:@"_placeholderLabel.textColor"]; |
但是在iOS13以后,系统对象通过KVC设置私有属性已被禁止。
取值
相对应的取值方式为-valueForKey:
、-valueForKeyPath:
,使用很简单
1 | person.age; |
-setValue:forKey:的原理
-setValue:forKey:
是Foundation
的函数,我们看不到源码,不过这个API的接口文档很详细。-setValue:forKey:
同时,在Foundation
的头文件中,函数的描述如下:
1 | /* Given a value and a key that identifies an attribute, set the value of the attribute. Given an object and a key that identifies a to-one relationship, relate the object to the receiver, unrelating the previously related object if there was one. Given a collection object and a key that identifies a to-many relationship, relate the objects contained in the collection to the receiver, unrelating previously related objects if there were any. |
我们可以结合文档,整理出-setValue:forKey:
内部的主要逻辑如下:
KVC底层调用willChangeValueForKey:
、didChangeValueForKey:
-valueForKey:的原理
-valueForKey:
函数核心原理和-setValue:forKey:
很类似,一个是设置值,一个是取值。它的原理如下:
KVC触发KVO的observer
KVC是键值编码、KVO的键值监听,从定义的描述可推测两者之前似乎有关联。他们关联也就是键值,一个是设置修改键值、一个是监听键值的修改。那么通过KVC修改属性会触发KVO么?答案是:会
1 | // 添加KVO监听 |
我们在KVO
的那一章中介绍过,触发KVO的关键代码是-willChangeValueForKey:
,-didChangeValueForKey:
,
1 | [self.person1 willChangeValueForKey:@"age"]; |
我们可以在person
的class中实现-willChangeValueForKey:
,-didChangeValueForKey:
,进行调试,结论是,通过KVC设置属性会调用这两个方法,也就会触发KVO
总结
知道KVC的调用顺序
通过KVC设置属性会触发KVO
源码和参考
apple document:setvalue