一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第24天,点击查看活动详情。
前言
KVC(Key Value Coding),即键值编码。提供了一个不通过getter和setter,而是属性名或键来间接访问对象的属性的机制。
KVC很好用,这种机制方便我们做很多事,比如帮助我们简化代码、解耦代码以及做一些正常操作做不了的事情(奸笑脸)。
但是由于KVC需要我们硬编码字符串,在编译期间无法检查合法性,所以大家都是一个手抖,就出现我们最最痛恨的Crash(沮丧脸)。
为了跟KVO引起的Crash永远说拜拜,我们将在本篇文章中讨论KVO引起Crash的原因,以及做好防护,解决这些Crash。
KVC 基础Setter方法的搜索模式
在执行setValue:forKey:方法时,默认会将key和value作为参数输入,并尝试在接收调用的对象中寻找属性key,并将value设置给这个属性。
查找属性key的过程如下:
-
按顺序查找名称为
set<Key>:、_set<Key>:的方法。- 如果找到,则使用
value(或由value的解包值)设置给属性,完成执行setValue:forKey:方法。 - 如果没有找到,则执行下一步。
- 如果找到,则使用
-
如果类方法
accessInstanceVariablesDirectly返回YES,则按顺序查找名称为_<key>、_is<Key>、<key>或is<Key>的实例变量。- 如果找到,则使用
value(或由value的解包值)设置给属性,完成执行setValue:forKey:方法。 - 如果未找到,或
accessInstanceVariablesDirectly返回NO,则执行下一步。
- 如果找到,则使用
-
调用
setValue: forUndefinedKey:方法,该方法默认会抛出异常NSUndefinedKeyException。
KVC 基础Getter方法的搜索模式
在执行valueForKey:方法时,默认会将key作为参数输入,并尝试在接收调用的对象内部执行如下过程:
-
按顺序查找名称为
get<Key>、<key>、is<Key>或_<key>的方法。-
如果找到,则调用该方法并使用结果执行步骤5。
-
否则执行下一步。
-
-
查找名称如
countOf<Key>、objectIn<Key>AtIndex:、<key>AtIndexes:的方法。-
如果找到了方法
countOf<Key>,并且至少找到了objectIn<Key>AtIndex:和<key>AtIndexes:中的一个,系统就会创建一个实现了NSArray所有方法的集合代理对象,并将该对象返回。 -
否则执行步骤3。
-
-
查找名称如
countOf<Key>,enumeratorOf<Key>, 和memberOf<Key>:方法。-
如果这三个方法都被找到,系统就会创建一个实现了
NSSet所有方法的集合代理对象,并将该对象返回。 -
否则执行步骤4。
-
-
如果类方法
accessInstanceVariablesDirectly返回YES,则按顺序查找名称为_<key>、_is<Key>、<key>或is<Key>的实例变量。-
如果找到,则直接获取实例变量的值并执行步骤5。
-
如果没找到,或者
accessInstanceVariablesDirectly返回NO,执行步骤6。
-
-
分为如下三种情况:
-
如果返回的属性值是对象的指针,则直接返回结果。
-
如果返回的属性值是
NSNumber支持的基础数据类型,则将其存储在NSNumber实例中并返回该值。 -
如果返回的属性值是
NSNumber不支持的数据类型,则转换为NSValue对象并返回该对象。
-
-
如果上述步骤都失败了,调用
valueForUndefinedKey:,该方法默认抛出异常NSUndefinedKeyException。