美文网首页iOS 底层原理探究
KVC(三)取值操作的实现

KVC(三)取值操作的实现

作者: PerryMorning | 来源:发表于2019-11-14 23:17 被阅读0次

    前两篇文章主要讲解了KVC的基本使用和赋值操作的实现,今天我们来看一下 - (nullable id)valueForKey:(NSString *)key;是如何通过key进行取值的。

    其步骤大致如下:

       1、首先会在接收者的方法列表中,依照 getKey()、key()、isKey()、_key()的顺序,去寻找方法的实现,找到其中一个的话,将其值返回给key对应的属性。

        2、假如第一步查找失败,会在方法列表中查找

               a: -countOf<Key>:(id)key 、

               b: -indexIn<Key>OfObject:()    

               c: -objectIn<Key>AtIndex:(NSInteger)index、

               d: -<key>AtIndexes:(NSInteger)index。

    如果找到方法a和b,并且c 和 d至少一个方法,会返回一个NSKeyValueOrderedSet类型的对象A。

    当调用集合对象A的count()/objectAtIndex/indexOfObject 等集合方法时,就会调用我们方法列表中实现的对应方法,并将其值返回。

        3、假如第二步没有找到对应的方法,只是找到了方法a和c/d中的至少一个方法,会返回一个NSKeyValueArray类型的对象。并执行对应的集合对象操作,类似于第二步。

        4、加入第三步查找失败,会继续查找以下三个方法:

             a: -countOf<Key>:(id)key;

             b:-enumeratorOf<Key>;

             c:-memberOf<Key>:

        如果三个方法全都存在,会返回一个NSKeyValueSet类型的集合对象,当调用集合的方法时,会调用以上三个方法的实现。

        5、当第四步执行失败,就会访问 +accessInstanceVariablesDirectly(),  当该方法返回YES时,会从对象的成员方法列表中以 _<key>, _is<Key>, <key>, or is<Key>的顺序进行查找匹配,如果找到则返回对应的值。

        6、如果第五步查找失败,会调用 -valueForUndefinedKey(),方法,该方法默认会抛出NSUndefinedKeyException异常,导致程序崩溃。我们可以通过重写此方法,避免程序崩溃。

    以上6步就是通过KVC取值的全部过程。

    下面我们通过代码来验证。

    首先验证步骤一:以height属性为例,在Person类中实现getHeight(),height(),isHeight()和_height()方法。

    当我们依次将方法注释后,得到的结果为:111、222、333、444。证明按顺序取值,找到对应方法后,即返回给valueForKey()。

    步骤二:假如没有实现以上四个方法,我们以numbers属性为例,声明并实现以下四个方法:

    调用valueForKey方法,得到NSKeyValueOrderedSet类型实例,与步骤二结果吻合:

    假如我们没有实现numbersAtIndexes:() 或者 objectInNumbersAtIndex()方法,同样的调用,结果也是一样的。

    步骤三:假如只实现了-(NSUInteger)countOfNumbers;,同时实现了-(id)objectInNumbersAtIndex:(NSUInteger)index;和- (id)numbersAtIndexes:(NSInteger)index;中的至少一个,再次调用会得到如下结果:

    步骤四:假如在接收者中只有以下三个方法实现:

    同样的调用会得到类NSKeyValueSet的实例,与步骤4推论吻合。

    步骤五:仍旧以numbers为例,在Person类中声明四个成员变量,并对其赋值:

    可以依次将_key,_isKey,key,isKey方法注释,查看结果进行验证。

    注意+ (BOOL)accessInstanceVariablesDirectly()默认返回值为YES,如果我们重写其方法将其返回NO时,会触发-valueForUndefinedKey()方法。

    步骤六:如果+ (BOOL)accessInstanceVariablesDirectly()依旧返回YES,但是并没有找到对应的属性时,依旧会触发-valueForUndefinedKey()方法。

    以上就是valueForKey:(NSString*)key 的全部调用过程。中间省去了一些调试变化的过程,各位朋友可以调试各种情况试一下,相信会有新的发现。

    虽然按照文档,将整个调用过程用代码翻译了一遍,但是在这里,笔者仍有一个疑问,在通过成员变量取值之前,为什么会先去尝试判断集合属性,这样的设计,是为了什么?有知晓答案的朋友吗,希望能够一起探讨。

    相关文章

      网友评论

        本文标题:KVC(三)取值操作的实现

        本文链接:https://www.haomeiwen.com/subject/xnjdictx.html