这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战
Hi 👋
| 我的个人项目 | 扫雷Elic 无尽天梯 | 梦见账本 |
|---|---|---|
| 类型 | 游戏 | 财务 |
| AppStore | Elic | Umemi |
一、 KVC set/get 过程
NSObject 的分类提供了 NSKeyValueCoding协议 的默认实现。
本文中的描述使用
<key>或<key>作为键字符串的占位符,该字符串在键值编码协议方法之一中作为参数出现,然后该方法将其用作辅助方法调用或变量名称查找的一部分。映射的属性名称遵循占位符的大小写。例如,对于 getter<key>和is<key>,名为hidden的属性映射到hidden和isHidden。
1.1 基本 Getter 的搜索过程
valueForKey: 的默认实现,给定一个key参数作为输入,执行以下过程。
步骤1
在实例中按顺序搜索方法:
- get
<key> <key>- is
<key> - _
<key>
如果找到,则调用它并使用结果继续执行步骤 5,否则继续下一步
验证一下
@interface RYModel : NSObject {
@public
NSString *_name;
NSString *name;
NSString *isName;
NSString *_isName;
}
@end
步骤2
在实例中搜索名称
- countOf
<key>和 - objectIn
<key>AtIndex: <key>AtIndexes:
对应于
NSArray
如果找到这些中的第一个和其他两个中的至少一个,则创建一个响应所有NSArray方法的集合代理对象并返回该对象。否则,继续执行 步骤 3
代理对象随后将任何 NSArray 接收到的一些组合的消息 countOf<key> , objectIn<key>AtIndex: 和 <key>AtIndexes: 消息给键-值编码创建它兼容的对象。
如果原始对象还实现了一个可选的方法,其名称类似于 get<key>:range: ,则代理对象也会在适当的时候使用它。
实际上,与
KVC兼容的对象一起工作的代理对象允许底层属性表现得好像它是NSArray,即使它不是。
步骤3
如果没有找到简单的访问方法或阵列访问方法组,寻找:
- countOf
<key> - enumeratorOf
<key> - memberOf
<key>
对应于
NSSet类
如果找到所有三个方法,则创建一个响应所有 NSSet 方法的集合代理对象并返回该对象。否则,继续执行步骤 4
此代理对象随后将任何 NSSet 接收到的一些组合信息 countOf<key> , enumeratorOf<key> 和 memberOf<key>: 消息以创建它的对象。
实际上,与
KVC兼容的对象一起工作的代理对象允许底层属性表现得好像它是NSSet,即使它不是。
步骤4
如果前面都没有找到,且类方法 accessInstanceVariablesDirectly 返回 YES(默认) ,按顺序查找名为
- _
<key> - _is
<key> <key>- is
<key>
的成员变量,如果找到,直接获取实例变量的值并进行步骤5,否则进行步骤6。
验证
步骤5
如果检索到的属性值是一个对象指针,只需返回结果即可。
如果该值是 NSNumber 支持的基础数据类型,则将其存储在一个 NSNumber 实例中并返回该实例。
如果结果是 NSNumber 不支持的数据类型,则转换为 NSValue 对象并返回。
步骤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。