in iOS

JSONModel 初始化流程分析

JSONModel 是一个 iOS 端的 JSON 序列化/反序列化开源库,最近在项目使用时遇到了一些问题,因此把代码看了看(使用的版本为0.9.0),特此记录。

这里主要说说创建流程。当拿到一个 JSON 字典时,我们使用 -(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err 方法进行初始化,所有的初始化流程都在这里完成。

一、准备环节

1.键名映射(包括全局的和当前类的),通过 JSONKeyMapper 管理。例如类中定义的是 name 而 JSON 中定义的 key 为 id_name,通过映射关系找到对应属性赋值。

2.检查数据是否包含所有 require 键值(键值已经过 KeyMapper 映射处理),如果不完整,则报错返回。

二、主循环体部分

for 循环主体,遍历当前类的所有属性,根据不同情况分别处理赋值。

2.1 首先取出字典中对应键值

从 JSON dict 中取出属性 name 对应的 value:

1.如果属性为 nil,且为 optional,那么跳过这个属性

2.检查 value 的类型是否是有效的,如果无效,则报错返回 nil,以下是有效的类型,在 JSONModel +load 方法中初始化:

2.2 设置值

真正的设置方法从这里开始,根据不同的情况,有不同的处理方法。

2.2.1 通过子类中的自定义 Setter 处理

如果有自定义的 Setter,则调用这个方法处理 value,然后 continue。

2.2.2 属性是基本类型(NSInteger, float 等)

如果属性的 type == nil && structName == nil ,即为原始类型,例如 NSInteger、float,直接 set 即可。

2.2.3 value 是空值

如果值为 nil 或者 NSNull,设置为 nil,(推测是为了覆盖原有值),注意,这种情况属性肯定不是 optional 的。

2.2.4.True 若属性是 JSONModel 子类

如果属性自身为一个 JSONModel 类,则自动生成对应类型的 JSONModel,然后将对应 value 传入 initWithDictionary 方法初始化

2.2.4.false 若不是 JSONModel 类:

2.2.4.1 属性拥有 Protocol

检查其是否拥有 protocol ,如果有,进入 __transform:forProperty 方法,在其中处理包含 JSONModel 字典或数组对象,例如这样的:@property (nonatomic, strong) NSArray<DidPGOOrder, Optional> *orders;,这时的 protocol 就是 DidPGOOrder

那么 __transform:forProperty 中都做了什么呢?

如果当前属性的类型是 NSArray,那么再根据属性中定义的转换方式做处理:

convertsOnDemand 方式表示传入的是 NSArray 类型,其中都是 JSONModel 对象。否则传入的为 NSArray,内容为 JSON 字典类型。

如果当前属性的类型为 NSDictionary,那么依次遍历所有键值,用 Protocol 类初始化,并将字典值传入。

最后,将生成好的 NSArray 或 NSDictionary value 返回,至此 __transform:forProperty 方法完成。

2.2.4.2 处理 Objc 基本类型(NSString,NSNumber等)

判断其是否为基本 OC 类型,如果是,直接设置

2.2.4.3.true 尝试处理需要转换类型的情况

如果 value 与属性类型不对应,而且不为空,或者属性为 mutable,那么

  1. 尝试寻找其 OC 父类,包括 NSString, NSNumber, NSArray, NSDictionary, NSDate
  2. 尝试构建一个 selector:”(structName || type) From sourceClass”,即从当前value是否可以转换为当前 属性的对应类
  3. 检查是否有这个方法,如果有,那就成功转换,然后 setValue
  4. 如果没有,抛异常,类型没有找到

2.2.4.3.false 剩余的其他情况

能试的都试过了,最终走到这里,就直接 setValue 吧。

for 循环体至此结束。

三、结尾部分

3.1 数据校验

运行类的校验方法,可以在子类 overwrite,默认总是返回成功。如果校验失败,则直接返回 nil。

3.2 返回结果

校验成功,可以返回结果啦,Congratulations!

原创文章,采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
转载请注明:转载自 Tony's blog,原文网址:https://itony.me/888.html