深入了解iOS中的KVC
KVC俗称键值编码,很多人都知道,也都用过,但是真的了解它的工作原理吗?
简单来说,一个对象如果直接或间接继承自NSObject,那么它就遵守了NSKeyValueCoding协议,并且系统会对该协议中的方法提供一个默认实现。
我们经常用的valueForKey:和valueForKeyPath:来获取值,就先来说说它们两个:
1.valueForKey:通过给定的参数key,来查找对应的值,如果发现就返回,否则就会调用valueForUndefinedKey:方法,该方法的默认实现会抛出NSUndefinedKeyException异常。但是子类是可以重写该方法的。
2.valueForKeyPath:通过给定的键路径,查找对应的值,如果找到就返回对应的值,否则也是执行valueForUndefinedKey:方法;其实该方法内部是调用valueForKey:来一步一步执行的。
以上两种方法用着简单,但是我们应该知道他们是怎么工作的。
第一步: 以get<Key>, is<Key>, <key>, <key>为名称来搜索访问器方法,如果找到就执行第五步,否则就执行第二步。
第二步: 第一步没有找到,就搜索方法名为countOf<Key>, objectIn<Key>AtIndex:, <key>AtIndexes:。如果第一个方法存在,并且后两个方法至少有一个存在,那么就会创建一个能响应NSArray所有方法的集合代理对象,并返回。否则就执行第三步。
第三步:该步会查找接收者是否实现了countOf<Key>, enumeratorOf<Key>, 和 memberOf<Key>:这三个方法。如果都实现了,就会创建一个能响应NSSet所有方法的集合代理对象,并返回。否则执行第四步。
第四步: 该步骤首先查看接收者的类方法+ (BOOL)accessInstanceVariablesDirectly是否返回YES,如果返回YES,就会以<key>, _is<Key>, <key>, is<Key>为实例变量名来进行查找,找到的话就执行第五步,否则就执行第六步。
第五步: 该步骤是对第一步和第四步查找到的值进行处理。
(1). 如果值是标量并且被NSNumber类支持,系统会将其转换成对应的NSNumber对象并返回。
(2). 如果值是标量但不被NSNumber类支持,系统会将其转换成对应的NSValue对象并返回。
第六步: 如果以上步骤都失败,就会调用valueForUndefinedKey:方法。
说完获取value,也要说说设置value:
设置value可以通过setValue:forKey:和setValue: forKeyPath:
1.setValue:forKey:是通过给定的key来对接收者进行查找,找到之后将value设置进去。
2.setValue: forKeyPath:内部通过调用setValue:forKey:来进行设置
注:以上两个方法没找到对应的key时,会调用setValue:forUndefinedKey:方法并抛出NSUndefinedKeyException异常
setValue:forKey:和setValue: forKeyPath:的搜索规则就简单许多:
第一步:通过set<Key>, set<Key>来查找存取方法,如果发现,调用它来设置值并结束。
第二步:如果第一步没有找到,则调用接收者的+ (BOOL)accessInstanceVariablesDirectly,如果返回YES,则以<key>, _is<Key>, <key>, or is<Key>为实例变量名来进行查找,如果找到则设置相应的值并结束。
第三步:如果以上都没有找到,就调用setValue: forUndefinedKey:方法。
注意:如果一个类的某个属性是标量或者结构体,系统的默认实现会帮助我们处理对象与标量或结构体的转换。