日常文章学习

KVC中的valueForKey方法中的坑

2018-06-05  本文已影响30人  烧烤有点辣
valueForKey这仇我记下了.png

本人在项目中创建了一个NSObject的分类,在分类中构建了一个方法:- (NSString *)getUserCode;用于返回一个用户标识。因为在项目中很多地方需要用到,顾封装在分类中,为了方便调用懒于在可以用类中进行#import操作,直接导入了PCH文件中(验证发现不导入也会有问题)。

坑就这样开始了

项目中有一个用于获取Model类的属性和对应的内容中,我使用了valueForKey方法来获取属性对应的值。

在这个Model中有一个属性名为userCode,当我使用valueForKey时,其实是为了获取当前属性的值,但是却运行了NSObject分类中的方法- (NSString *)getUserCode;因此数据造成了错误。

随后进行了一波网上操作,在一篇文章中提及:KVC原理剖析

  1. 这是valueForKey:的默认实现,给定一个key当做输入参数,开始下面的步骤,在这个接收valueForKey:方法调用的类内部进行操作。
    通过getter方法搜索实例,例如get, , is, _的拼接方案。按照这个顺序,如果发现符合的方法,就调用对应的方法并拿着结果跳转到第五步。否则,就继续到下一步。
  1. 如果没有找到简单的getter方法,则搜索其匹配模式的方法countOf、objectInAtIndex:、AtIndexes:。
    如果找到其中的第一个和其他两个中的一个,则创建一个集合代理对象,该对象响应所有NSArray的方法并返回该对象。否则,继续到第三步。
    代理对象随后将NSArray接收到的countOf、objectInAtIndex:、AtIndexes:的消息给符合KVC规则的调用方。
    当代理对象和KVC调用方通过上面方法一起工作时,就会允许其行为类似于NSArray一样。
  1. 如果没有找到NSArray简单存取方法,或者NSArray存取方法组。则查找有没有countOf、enumeratorOf、memberOf:命名的方法。
    如果找到三个方法,则创建一个集合代理对象,该对象响应所有NSSet方法并返回。否则,继续执行第四步。
    此代理对象随后转换countOf、enumeratorOf、memberOf:方法调用到创建它的对象上。实际上,这个代理对象和NSSet一起工作,使得其表象上看起来是NSSet。
  1. 如果没有发现简单getter方法,或集合存取方法组,以及接收类方法accessInstanceVariablesDirectly是返回YES的。搜索一个名为_、_is、、is的实例,根据他们的顺序。
    如果发现对应的实例,则立刻获得实例可用的值并跳转到第五步,否则,跳转到第六步。
  1. 如果取回的是一个对象指针,则直接返回这个结果。
    如果取回的是一个基础数据类型,但是这个基础数据类型是被NSNumber支持的,则存储为NSNumber并返回。
    如果取回的是一个不支持NSNumber的基础数据类型,则通过NSValue进行存储并返回。
  1. 如果所有情况都失败,则调用valueForUndefinedKey:方法并抛出异常,这是默认行为。但是子类可以重写此方法。

随之我也进行了代码验证:


model.h.jpg model.m.jpeg

这是一个Model的定义,之后使用valueForKey方法进行调用。

1528186850079.jpg

可以看出valueForKey确实调用了getUserCode本以为是“私有方法”的方法。如果不定义这个getUserCode方法,正常获取值。

1528187228671.jpg

刚刚我说我在分类中定义了- (NSString *)getUserCode;valueForKey此方法会直接寻找此方法进行调用。在验证中发现,只需要此方法文件存在项目就会调用,而不需要导入类。

因为较少的使用KVC,而从未注意到会有这样的操作。不过这应该是和iOS中的运行时Runtime有关系。 稍后研究下两者之间的关系。

所以在项目如果有使用了KVC,主要项目中的方法名是否与valueForKey:中传入的key是一样的,避免造成错误。
上一篇 下一篇

猜你喜欢

热点阅读