20.详解KVC
前言
一、 KVC set/get 过程
NSObject
的分类提供了 NSKeyValueCoding协议
的默认实现。
本文中的描述使用
<key>
或<key>
作为键字符串的占位符,该字符串在键值编码协议方法之一中作为参数出现,然后该方法将其用作辅助方法调用或变量名称查找的一部分。映射的属性名称遵循占位符的大小写。例如,对于 getter<key>
和is<key>
,名为hidden
的属性映射到hidden
和isHidden
。
1.1 基本 Getter 的搜索过程
valueForKey:
的默认实现,给定一个key参数作为输入,执行以下过程。
1.1.1
在实例中按顺序搜索方法
:
get
<key>
<key>
is
<key>
_
<key>
如果找到,则调用它并使用结果继续执行步骤 5,否则继续下一步
验证一下
1.1.2
在实例中搜索名称
countOf
<key>
和objectIn
<key>
AtIndex:<key>
AtIndexes:
对应于
NSArray
如果找到这些中的第一个和其他两个中的至少一个,则创建一个响应所有NSArray方法的集合代理对象并返回该对象。否则,继续执行 步骤 3
代理对象随后将任何 NSArray 接收到的一些组合的消息 countOf<key>
, objectIn<key>
AtIndex: 和 <key>
AtIndexes: 消息给键-值编码创建它兼容的对象。
如果原始对象还实现了一个可选的方法,其名称类似于 get<key>
:range: ,则代理对象也会在适当的时候使用它。
实际上,与
KVC
兼容的对象一起工作的代理对象允许底层属性表现得好像它是NSArray
,即使它不是。
1.1.3
如果没有找到简单的访问方法或阵列访问方法组,寻找:
countOf
<key>
enumeratorOf
<key>
memberOf
<key>
对应于
NSSet
类
如果找到所有三个方法,则创建一个响应所有 NSSet
方法的集合代理对象并返回该对象。否则,继续执行步骤 4
此代理对象随后将任何 NSSet
接收到的一些组合信息 countOf<key>
, enumeratorOf<key>
和 memberOf<key>
: 消息以创建它的对象。
实际上,与
KVC
兼容的对象一起工作的代理对象允许底层属性表现得好像它是NSSet
,即使它不是。
1.1.4
如果前面都没有找到,且类方法 accessInstanceVariablesDirectly
返回 YES(默认)
,按顺序查找名为
_
<key>
_is
<key>
<key>
is
<key>
的成员变量,如果找到,直接获取实例变量的值并进行步骤5,否则进行步骤6。
验证
1.1.5
如果检索到的属性值是一个对象指针,只需返回结果即可。
如果该值是 NSNumber
支持的基础数据类型,则将其存储在一个 NSNumber
实例中并返回该实例。
如果结果是 NSNumber
不支持的数据类型,则转换为 NSValue
对象并返回。
1.1.6
如果所有其他方法都失败,请调用 valueForUndefinedKey:
。 默认情况下,这会引发异常,但NSObject的子类可能会提供特定于Key的处理。
1.2 基本 Setter 的搜索过程
setValue:forKey:
的流程按顺序查找方法
:
set
<key>
:_set
<key>
如果找到,调用。
验证方法查找
如果没有找到,如果类方法 accessInstanceVariablesDirectly
返回 YES(默认)
,按顺序寻找一个实例变量与名称类似:
_
<key>
_is
<key>
<key>
is
<key>
如果找到,设置。
验证变量查找
如果找不到,调用 setValue:forUndefinedKey:
。 默认情况下,这会引发异常,但 NSObject
的子类可能会提供特定于Key的处理。
二、 关于 accessInstanceVariablesDirectly 的思考
控制是否可以通过 KVC 给成员变量赋值,默认 YES
。
如果 NO,会怎样呢?
这里给了我一点启发,如果自己封装的一些东西不希望使用者通过 KVC
修改一些私有成员变量的话可以在这里返回 NO
。
参考
Last updated