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,否则继续下一步
验证一下
@interface RYModel : NSObject {
@public
NSString *_name;
NSString *name;
NSString *isName;
NSString *_isName;
}
@end



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
Was this helpful?