MoyaMapper是基于Moya和SwiftyJSON封装的工具,以Moya的plugin的方式来实现间接解析,支持RxSwift
一、概述
1、相信大家在使用Swift开发时,Moya是首选的网络工具,在模型解析这一块,Swift版模型解析的相关第三方库有很多,本人最习惯用的就是SwiftyJSON。
2、下面会开始讲解整个主要的开发功能与思想。
3、以下内容是基于大家会使用Moya和SwiftJSON的前提下所著,还不会的同学可以先简单了解后再来阅读本篇文章哦~
二、功能开发与思想讲解
1、尝试模型解析
Moya请求服务器返回的数据以Response类返回给我们,那我们就给Response类做一个扩展,这里以解析模型为例
1 | // 需要传入一个参数,告知我们要转换出什么模型 |
Q: 那中间的解析过程该怎么写呢?
A: 可以让开发者遵守某个协议,实现指定的转换方法并描述转换关系。其转换过程我们不需要知道,交给开发者即可。
那接着我们来定义一个协议Modelable,并声明转换方法
1 | public protocol Modelable { |
开发者创建一个MyMoel
的结构体,遵守协议Modelable
,并实现mapping
,书写转换关系
1 | struct MyModel: Modelable { |
以目前的现状来分析一下:mapObject
可以让开发者传入模型类型
,而我们的协议方法却并非是个类方法。那我们需要先得到这个模型类型
的对象,再来调用mapping
方法
2、模型解析的驱动开发
Q: 怎么得到这个对象?
A: 可以在协议中声明一个初始化方法来创建对象。是的,我们在mapObject中创建对应模型类型的对象,调用mapping方法来转换数据,再把模型对象传出去即可。
那我们在Modelable
中声明一个init方法,并传入一个参数,区别于其它初始化方法
1 | public protocol Modelable { |
OK,现在把mapObject
方法补齐模型解析过程
1 | public func mapObject<T: Modelable>(_ type: T.Type) -> T { |
3、自定义解析键名
Q: 这样是搞定解析了,但是网络请求回来的json格式错综复杂,有什么办法可以让开发者来自行指定model对应的键名呢?
A: 嗯嗯,既然解析过程是在 Response 扩展里操作的,那我们可以通过协议定义键名属性,并且使用 Runtime 给Response动态添加一个属性,来记录遵守协议后的相应类名
1 | public protocol ModelableParameterType { |
1 | // MARK:- runtime |
这里有个坑:_SwiftValue问题 (献上 参考链接)
如果我们存储的不是OC对象,那么objc_getAssociatedObject
取出来的值的类型统统为_SwiftValue
,直接as? ModelableParameterType.Type
绝对是nil,需要在取出来后as AnyObject
再转换为其它类型才会成功~~
现在开发者就可以创建一个类来遵守ModelableParameterType
协议,并自定义解析键名
1 | struct NetParameter : ModelableParameterType { |
4、插件注入
Q: 厉害了,不过要在什么时机下存储这个自定义键名的NetParameter
?
A: 额,这个~~~ 哦,对了,可以通过Moya提供的插件机制!
翻出Moya中的Plugin.Swift,找到这个process
方法,看看方法说明。
1 | /// 在结束之前,可以被用来修改请求结果 |
那好,我们也做一个插件MoyaMapperPlugin
给开发者使用,在创建MoyaMapperPlugin
时把自定义解析键名的类型传进来
1 | public struct MoyaMapperPlugin: PluginType { |
使用:开发者在创建MoyaProvider
对象时,顺便注入插件。(OS: 这一步堪称“注入灵魂”)
1 | MoyaProvider<LXFNetworkTool>(plugins: [MoyaMapperPlugin(NetParameter.self)]) |
5、总结
以上就是主要的踩坑过程了。模型数组解析和指定解析也跟这些差不多的,这里就不再赘述。本人已经将其封装成一个开源库 MoyaMapper,包含了上述已经和未曾说明的功能,下面会讲解如何去使用。以上部分可以称为开胃菜,目的就是平滑过渡到下面MoyaMapper的具体使用。
可能单单使用MoyaMapper
的默认子库Core
,作用体会上并不会很深。但是,如果你也是使用RxSwift来开发项目的话,请安装'MoyaMapper/Rx'
吧,绝对一个字:「爽」
二、MoyaMapper的使用
MoyaMapper是基于Moya和SwiftyJSON封装的工具,以Moya的plugin的方式来实现间接解析,支持RxSwift
1、定义并注入自定义键名类
- 定义一个遵守ModelableParameterType协议的结构体
1 | // 各参数返回的内容请参考上面JSON数据对照图 |
此外,这里还可以做简单的路径处理,以应付各种情况,以’>’隔开
1 | // 假设返回的json数据关于请求状态的相关数据如下所示, |
1 | // 我们指明解析路径:error对象下的errMsg字段,一层层表示下去即可 |
- 以plugin的方式传递给MoyaProvider
1 | // MoyaMapperPlugin这里只需要传入类型 |
2、定义解析模型
创建一个遵守Modelable协议的结构体
1 | struct MyModel: Modelable { |
3、解析数据
0x00 请求结果与模型解析
1 | // Result |
上面的五个方法,观其名,知其意,这里就不过多解释了,主要注意两点:
result
swift1
2
3
4// 元祖类型
// 参数1:根据statusCodeKey取出的值与successValue是否相等
// 参数2:根据tipStrKey取出的值
result:(Bool, String)params
swift1
2// params: ModelableParamsBlock? = nil
// 这里只有在特殊场景下才需要使用到。如:项目中需要在某处使用特定接口,但是返回的json格式跟自己项目的不一样,并且只有这么一两处用得着该额外接口,那就需要我们这个参数了,以Block的方式返回解析参数类型。
0x01、特定解析
1 | // Model |
这两个方法,如果没有指定路径,默认都是针对modelKey的
1 | // fetchJSONString(keys: <[JSONSubscriptType]>) |
MoyaMapper也提供了Rx子库,为方便RxSwift的流式编程下便捷解析数据
1 | MoyaMapper默认只安装Core下的文件 |
具体使用还不是很明白的同学可以下载并运行Example
看看
如果MoyaMapper有什么不足的地方,欢迎提出issues,感谢大家的支持