无意看到KVC原理的文章,发现很多中文文章说的都不全面,翻了一下官网文档,记录一下
basic getters
基础的valueForKey:
1.搜寻实例对象存取方法,搜寻的方法名顺序为:get<Key>
,<key>
,is<Key>
或者_<key>
,如果搜寻到了类似的方法,将结果带入第5步。否则进行下一步
2.如果没有找到简单的访问器方法,开始寻找符合countOf<Key>
,objectIn<Key>AtIndex:
(与NSArray类的初始方法相对应地方法,参数也与NSArray的对应方法一样)和<key>AtIndexs:
(与NSArray的objectsAtIndexes:
对应)这种命名规则的方法。如果第一个方法(countOf<Key>
)和剩下两个方法中的至少一个被发现了,创建一个能够响应所有NSArray方法的集合代理对象返回(断点调试看到的是NSKeyValueArray对象)。如果没有,进入第三步
上面创建的代理对象随后将它收到的所有NSArray相关的消息(调用)转换成创建它的那个符合kvc规则的对象中countOf<Key>
,objectIn<Key>AtIndex:
和<key>AtIndexs:
的消息结合。如果原始的对象还实现了一个可选方法名字符合get<Key>:range:
的范式,该代理对象在适当的时候也会使用改方法。实际上,这个代理对象和这个符合kvc规则的对象共同工作,允许下面的属性像一个NSArray一个呈现,即使那个属性并不是array。
3.如果简单的访问器方法和上述数组访问方法都没有,则开始搜寻三个名为countOf<Key>
,enumeratorOf<Key>
和memberOf<Key:>
的方法(与NSSet中的原始方法相对应)
如果三个方法都实现了,创造一个能够响应所有NSSet方法的集合代理对象返回(这里没做实验)。否则进入第4步
这个代理对象随后将收到的所有NSSet消息(调用)转换成创造它的那个对象中countOf<Key>
,enumeratorOf<Key>
和memberOf<Key>:
消息的组合。实际上,这个代理对象和这个符合kvc规则的对象共同工作,允许下面的属性像一个NSSet一个呈现,即使那个属性并不是set
4.如果上述的简单访问器方法和集合访问方法都没有找到,并且这个消息接收者的accessInstanceVariablesDirectly
返回YES,那么按照_<key>
,_is<Key>
,<key>
,或者is<Key>
的顺序搜寻符合的实例变量。如果找到了,直接获取改实例变量进入第5步,如果没有,进入第6步。
5.如果返回的值是一个对象指针,直接返回
如果返回的是一个可以被包装成NSNumber的基础类型,包装成NSNumber返回
如果返回的是一个不能被包装成NSNumber的基础类型,转换成一个NSValue对象返回
6.如果上面所有的都失败了,调用valueForUndefinedKey:
方法,这个方法默认会生成一个异常(crash在这方法里),不过NSObject的子类可以继承根据key做一些特定处理。
basic setter
setValue:forKey:
1.首先按顺序查找名为set<Key>:
或者_set<Key>:
方法,如果存在,将输入的值(或者解除封装,例如setvalue
中传的一个NSNumber,set<Key>:
中接收的是一个NSInteger)传入方法中调用。
2.如果简单的存取方法没找到,并且类的accessInstanceVariablesDirectly
返回YES,按照_<key>
,_is<Key>
,<key>
,或者is<Key>
的名字顺序查找实例变量。如果找到了,直接设置变量值为输入值并且结束。
3.如果存取方法和实例变量都没找到,调用setValue:forUndefinedKey:
方法,这个方法默认会生成一个异常,不果继承NSObject的子类可以根据key提供一些特定的处理
待续,后面还有为集合类set方法。