字典模型转换库-MJExtension的使用和原理详解

    在日常的iOS开发中,总会进行数据的转换,比如请求服务端获取数据,解析数据,转换成对应的model,这个转换过程比较繁琐,重复工作较多,今天给大家介绍一个很好用的JSON转换库MJExtension。

    MJExtension是一套字典和模型之间互相转换的超轻量级框架,利用runtime进行数据之间的转换,,使用简单无侵入,使用门槛较低,下面简单介绍下MJExtension的功能。

MJExtension的功能介绍

下面是MJExtension的功能,包括将JSON --> Model,Dictionary -->Model,Model -->JSON,JSON Array --> Model Array 等等功能。

JSON --> Model、Core Data Model

JSONString --> Model、Core Data Model

Model、Core Data Model --> JSON

JSON Array --> Model Array、Core Data Model Array

JSONString --> Model Array、Core Data Model Array

Model Array、Core Data Model Array --> JSON Array

MJExtension的使用

在MJExtension中,我们使用的api都在NSObject+MJKeyValue.h文件中,里面有详细的注释,这里就不多说了。下面我们就用微博的数据举例子,进行使用讲解

1.简单的字典 -> 模型(模型中的属性都是基本类型)

1)首先我们看下字典转模型,只需要一行代码就可以,十分简洁方便,这里需要注意下,model中的对应属性和字典中的key要相同,调用mj_objectWithKeyValues

字典模型转换库-MJExtension的使用和原理详解_第1张图片
字典转模型
字典模型转换库-MJExtension的使用和原理详解_第2张图片
User的model

2)假如我们觉得MJUser中的属性命名有些歧义,不是很好,这时候我们想改一下,比如字典中的name叫jack,可能对应属性叫firstname更好,这时候,我们就需要在字典转模型的时候,进行属性名的替换,我们可以这么做,在MJUser.m文件中实现mj_replacedKeyFromPropertyName方法,方法如下图所示

字典模型转换库-MJExtension的使用和原理详解_第3张图片
将name用firstname替换
转换过程替换字典中的key值

3)如果在转换过程中,我们只想对部分属性,进行转换,比如,你只需要firstname和icon,name可以使用如下方法进行设置,mj_allowedPropertyNames或者mj_ignoredPropertyNames,这两个方法可以看做白名单和黑名单的方法

字典模型转换库-MJExtension的使用和原理详解_第4张图片
mj_allowedPropertyNames和mj_ignoredPropertyNames方法

MJUser.m文件中实现mj_allowedPropertyNames方法,即可只转换firstname和icon

只转换firstname和icon属性

4)如果在字典转model的过程中,你需要改变firstname的值,在每个 firstname前面加上一段文字,比如:“jack”变成我是“我的名字是jack”,这时候可以使用mj_newValueFromOldValue方法,下面在MJUser.m文件中实现mj_newValueFromOldValue方法,每次进行转换的时候,都可以在firstname前加上“我的名字是”,或者还可以做一些其它的处理

字典模型转换库-MJExtension的使用和原理详解_第5张图片
在firstname前加上“我的名字是”

5)如果在字典转换为model完成后,想做一些其它事情,可以使用mj_keyValuesDidFinishConvertingToObject方法进行。

2.复杂的字典 -> 模型

    除了上面的简单字典转模型,还有些复杂的模型,比如字典中包含字典和数组,这种情况,我们怎么处理呢???

1)首先我们看一下,下面这种数据结构,复杂的字典 -> 模型 (模型里面包含了模型)

字典模型转换库-MJExtension的使用和原理详解_第6张图片
MJStatus的数据结构

这是一个字典嵌套字典的结构,它需要转成一个模型嵌套模型的结构

字典模型转换库-MJExtension的使用和原理详解_第7张图片
MJStatus的模型

只需要调用mj_objectWithKeyValues方法即可,跟简单模型使用方法一致,其它都不需要我们做,至于模型嵌套模型这种结构的转换时怎么实现的,我会在下一部分,讲解原理的时候说到。

2)下面我们看一下,复杂的字典 -> 模型 (模型的数组属性里面又装着模型)

字典模型转换库-MJExtension的使用和原理详解_第8张图片
模型的数组属性里面又装着模型
字典模型转换库-MJExtension的使用和原理详解_第9张图片
MJStatusResult模型

我们可以看到,上面MJStatusResult模型中的statuses属性和ads属性,都是一个array,而array中的每一个元素都是一个模型,比如statuses中是一个MJStatus模型,ads中是MJAd模型,在进行MJStatusResult模型的转换过程中,我们需要设置数组属性的模型的类型,这时候我们需要用到mj_objectClassInArray方法,指定数组属性中元素的模型类型,具体用法如下:

字典模型转换库-MJExtension的使用和原理详解_第10张图片
statuses的元素是一个MJStatus,ads中的元素是MJAd

3.模型 -> 字典

模型转字典主要有一下几个方法,用法类似,这里就不多讲了,大家可以看下源码。

字典模型转换库-MJExtension的使用和原理详解_第11张图片
模型转字典的方法

MJExtension的原理

MJExtension中类说明

在分析原理之前,我们先看下文件的MJExtension的文件组成,以及每个文件的作用。

字典模型转换库-MJExtension的使用和原理详解_第12张图片
MJExtension的所有文件

1.MJExtension.h 只是引用了一些头文件,方便管理。

2.MJExtensionConst.h和MJExtensionConst.m 声明了一些宏定义,用来抛出异常和做判断用的,同时声明和定义了一些属性类型。

3.MJFoundation.h和MJFoundation.m文件主要是用来判断某个类是否是来自Foundation库中的基本类型,在进行字典和模型的转换过程中,会根据这个类来判断是否是模型嵌套模型的结构。

4.MJProperty.h和MJProperty.m是一个记录属性信息的类,包含属性的的所有信息,比如,属性类型,名字,来源等等。

5.MJPropertyKey.h和MJPropertyKey.m提供一个根据属性key,返回属性值的方法。

6.MJPropertyType.h和MJPropertyType.m是记录一个属性的类型,比如MJProperty中属性类型就是用MJPropertyType来记录的,MJPropertyType类中包含类型标识符,是否为基本数字类型,来源框架,是否支持KVC等等,在字典和模型转换中,提供属性类型信息。

7.NSObject+MJClass.h和NSObject+MJClass.m用来遍历所有类,并进行黑名单和白名单的管理。

8.NSObject+MJCoding.h和NSObject+MJCoding.m主要是对属性值进行归档和解档,并且可以对属性名字添加黑名单和白名单。

9.NSObject+MJKeyValue.h和NSObject+MJKeyValue.m类中提供了所有模型和字典之间转换的接口,上面讲的使用方法,都是来自与这个类的接口,我们需要熟悉里面的所有接口,以便可以更好的使用它。

10.NSObject+MJProperty.h和NSObject+MJProperty.m是遍历模型所有成员,获取模型中的属性,用MJProperty类保存属性,用于进行字典和模型转换。

11.NSString+MJExtension.h和NSString+MJExtension.m是用来进行属性名字转换的类,比如讲驼峰格式的类名,转换为下划线的命名格式。

MJExtension模型字典转换过程

1.使用runtime 获取模型的所有属性 ,转换成MJProperty属性模型列表

2.根据MJProperty中的属性类型,对属性进行处理,获取属性值。

3. 根据属性名字,通过KVC对属性赋值。

1.runtime如何获取所有属性

首先我们看下MJExtension的源码,NSObject+MJProperty类中的+ (NSMutableArray *)properties方法。

字典模型转换库-MJExtension的使用和原理详解_第13张图片
通过Class获取模型的属性

1)首先使用runtime中的class_copyPropertyList方法,获取类的所有属性,class_copyPropertyList方法会返回一个objc_property_t类型的对象,这是一个结构体,如下所示

objc_property

objc_property是一个结构体,是一个内置的类型,与之关联的还有一个objc_property_attribute_t,它是属性的attribute,也就是其实是对属性的详细描述,包括属性名称、属性编码类型、原子类型/非原子类型等。它的定义如下:

objc_property_attribute_t

2)然后遍历每个成员,将objc_property_t中的属性,转换成MJProperty对象,转换过程如下:

字典模型转换库-MJExtension的使用和原理详解_第14张图片
objc_property_t转换成MJProperty

首先使用property_getName获取属性名,然后使用property_getAttributes获取objc_property_attribute_t,为一个字符串的结果,里面包含属性名称、属性编码类型、原子类型/非原子类型等,比如:NSString类型的属性,对应的attrs为T@"NSString",C,N,V_icon。下面我解释一下这个字符串对应的意思:

T 表示属性的类型 类型为基本对象类型和基本数据类型,基本对象类型的value为该对象类型名字 如NSArray、NSString、NSMutableDictionary 等

C 表示该属性为copy ;为&表示属性为strong;W表示属性为weak;空 表示属性为assgin

N表示为非原子属性

V表示属性的名字 此时value为加了下划线的属性名字

最后会根据property_getAttributes信息生成属性对象的type。

2.根据MJProperty中的属性类型,对属性进行处理,获取属性值。

根据属性类型,对属性进行处理主要在- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context 方法中进行的,如下所示:

字典模型转换库-MJExtension的使用和原理详解_第15张图片
字典模型转换库-MJExtension的使用和原理详解_第16张图片
对属性赋值的过程

从上面代码可以看出

1)通过valueInObject获取属性值value,

2)获取到值以后,做了一些特殊处理

将value由可变对象转换成不可变类型

如果value是模型,则继续将value转换成模型。

如果模型类型是NSString类型,会将属性类型中的NSNumber和NSURL转换为NSString。

如果模型类型是NSURL类型,会将属性类型中NSString转换为NSURL。

如果模型类型是NSNumber类型,会将属性类型中NSString转换为NSNumber。

如果模型类型是NSNumber类型,会将属性类型中NSString转换为NSNumber。

如果模型类型是BOOL类型,会将字符串和yes,true,no,false进行匹配,转换为BOOL类型

如果模型类型和属性类型不匹配,会将value设置为nil。

3. 根据属性名字,通过KVC对属性赋值。

接下来,会使用属性值value,为属性赋值,如下所示:

字典模型转换库-MJExtension的使用和原理详解_第17张图片

首先会判断是否支持KVC,如果支持会给属性赋值。

到这里就讲解完了MJExtension的使用和原理

你可能感兴趣的:(字典模型转换库-MJExtension的使用和原理详解)