最近在做项目的过程中,有用到以key-value的形式初始化对象,常规做法就是实现一份儿解析根据不同的映射初始化不同的变量。但由于我们需要让使用方更大的简化调用方式,所以引入了该方法来实现这些功能。其实就是用了一些oc语言的特性来处理这些事情。
为什么提出
由于在处理一些特有逻辑的时候,我们需要用一些key-value的形式或者配置文件来初始化对象,而传统的encode和decode方法则需要在类里边根据自己的实现来实现一份儿代码。所以我们需要一个独立的模块来出来该类问题。要么是不方便,要么是代码过于分散不便管理
从 0 到 1
我们可以定制一个映射规则,这篇文章内的映射规则是这样的
以array的形式传入要初始化的参数,参数的item为一个map类型。map的定义格式为key为对应对象内的property,value则为我们要初始化成的值
当然为了保险起见,我们也可以在找不到property的情况下查找类是否有key对应的成员变量,然后对其进行初始化
接下来
我们先来看看如下的代码
其中objc_property_t类型是一个系统类型的指针,对开发者是不可见的,但是apple为我们提供了一系列的方法来处理它,我们来看看都有哪些方法可以处理它,我在注释里做了一个简单的介绍
其中objc_property_attribute_t的定义如下
这里我们用到了property_getAttributes方法,所以将property_getAttributes方法的返回值着重说一下,当我们调用该方法时,它的返回值一般是这个样式的
当我们重写了setter和getter方法后,我们还会看到*G*和*S*,尖括号内为我们自定义的setter或getter方法
如*ScustomSetter:*表示我们重写了*setter*方法为customSetter:
动手实现
有了上述的基础知识作为铺垫后,我们就可以开始实现我们的初始化模块了
- 定义映射规则
- 根据key找到类中的propery(成员变量下次说)
- 根据propery获取到property属性,获取正确的setter方法和数据类型
- 调用perform或者msg_send方法进行复制
具体实现代码,可以参考下边实现
上述代码做一些说明,我们调用了objc_msgSend方法来调用类或者对象的set方法,在64-bit运行环境中,我们可以了解到所有的方法必须有明确的定义,所以xcode6以后做了一个限制,不可直接调用该方法。具体可以参见该方法的定义。那我们为了调用该方法该怎么做呢。这里有两种方案:
- 将objc_msgSend方法转换成有明确定义的函数指针,然后再进行调用
- 在build setting 中关闭xcode的objc_msgSend方法直接调用检查
推荐使用第一种方法,因为第二种方法违背了64-bit的那个规定,会存在潜在风险
property_getAttributes的一些说明