Moya在Swift开发中起着重要的网络交互作用,但是还有不如之处,比如网络不可用时,返回的Response为nil,这时还得去解析相应的ErrorCodable可以帮助我们快速的解析数据,但是一旦声明的属性类型与json中的不一致,将无法正常解析; 而且对于模型中自定义属性名的处理也十分繁琐
Moya在Swift开发中起着重要的网络交互作用,但是还有不如之处,比如网络不可用时,返回的Response为nil,这时还得去解析相应的ErrorCodable可以帮助我们快速的解析数据,但是一旦声明的属性类型与json中的不一致,将无法正常解析; 而且对于模型中自定义属性名的处理也十分繁琐
解决的方案有很多,不过我比较习惯使用 MoyaMapper ,不仅可以解决上述问题,还提供了多种模型转换、数据互转、多种数据类型任意存储的便捷方法。掌控Moya的网络请求、数据解析与缓存简直易如反掌。
MoyaMapper是基于Moya和SwiftyJSON封装的工具,以Moya的plugin的方式来实现间接解析,支持RxSwiftGitHub: MoyaMapper
📖 详细的使用请查看手册 https://MoyaMapper.github.io
特点
- 支持
json转Model自动映射 与 自定义映射 - 无视
json中值的类型,Model中属性声明的是什么类型,它就是什么类型 - 支持
Data字典JSONjson字符串Model互转 - 插件方式,全方位保障
Moya.Response,拒绝各种网络问题导致Response为nil,将各式各样的原因导致的数据加载失败进行统一处理,开发者只需要关注Response - 可选 - 支持数据随意缓存(
JSON、Number、String、Bool、Moya.Response) - 可选 - 支持网络请求缓存
数据解析
一、插件注入
1、定义适用于项目接口的 ModelableParameterType
1 | // statusCodeKey、tipStrKey、 modelKey 可以任意指定级别的路径,如: "error>used" |
2、在 MoyaProvider 中使用 MoyaMapperPlugin 插件,并指定 ModelableParameterType
1 | let lxfNetTool = MoyaProvider<LXFNetworkTool>(plugins: [MoyaMapperPlugin(NetParameter())]) |
❗ 使用 MoyaMapperPlugin 插件是整个 MoyaMapper 的核心所在!
二、Model声明
Model需遵守Modelable协议
MoyaMapper支持模型自动映射 和 自定义映射- 不需要考虑源json数据的真实类型,这里统一按
Model中属性声明的类型进行转换
1、一般情况下如下写法即可
1 | struct CompanyModel: Modelable { |
2、如果自定义映射,则可以实现方法 mutating func mapping(_ json: JSON)
1 | struct CompanyModel: Modelable { |
3、支持模型嵌套
1 | struct UserModel: Modelable { |
三、Response 解析
1、以下示例皆使用了
MoyaMapperPlugin,所以不需要指定解析路径2、如果没有使用
MoyaMapperPlugin则需要指定解析路径,否则无法正常解析ps:
解析路径可以使用a>b这种形式来解决多级路径的问题
解析方法如下列表所示
| 方法 | 描述 (支持RxSwift) |
|---|---|
| toJSON | Response 转 JSON ( toJSON rx.toJSON) |
| fetchString | 获取指定路径的字符串( fetchString rx.fetchString) |
| fetchJSONString | 获取指定路径的原始json字符串 ( fetchJSONString rx.fetchJSONString ) |
| mapResult | Response -> MoyaMapperResult (Bool, String) ( mapResult rx.mapResult ) |
| mapObject | Response -> Model ( mapObject rx.mapObject) |
| mapObjResult | Response -> (MoyaMapperResult, Model) ( mapObjResult rx.mapObjResult) |
| mapArray | Response -> [Model] ( mapArray rx.mapArray) |
| mapArrayResult | Response -> (MoyaMapperResult, [Model]) ( mapArrayResult rx.mapArrayResult) |
❗除了 fetchJSONString 的默认解析路径是根路径之外,其它方法的默认解析路径为插件对象中的 modelKey
如果接口请求后 json 的数据结构与下图类似,则使用 MoyaMapper 是最合适不过了
1 | // Normal |
1 | // Normal |
1 | // Normal |
统一处理网络请求结果
在APP的实际使用过程中,会遇到各种各样的网络请求结果,如:服务器挂了、手机无网络,此时
Moya返回的Response为 nil,这样我们就不得不去判断Error。但是使用MoyaMapperPlugin就可以让我们只关注Response
1 | // MoyaMapperPlugin 的初始化方法 |
- 当请求失败的时候,此时的
result.response为nil,根据transformError是否为true判断是否创建一个自定义的response并返回出去。
➡ 本来可以请求到的数据内容
➡ 现在关闭网络,再请求数据
正常情况下,即不做任何不处理的时候,
Response为nil经过
MoyaMapperPlugin处理的后可得到转换后的Response,如图
这里将请求失败进行了统一处理,无论是服务器还是自身网络的问题,retStatus 都为 MMStatusCode.loadFail,但是 errorDescription 会保持原来的样子并赋值给 retMsg。
retStatus值会从枚举MMStatusCode中取loadFail.rawValue,即700- 取 类型为
ModelableParameterType的type中statusCodeKey所指定的值 为键名,retMsg也同理
ps: 这个时候可以通过判断 retStatus 或 response.statusCode 是否与 MMStatusCode.loadFail.rawValue 相同来判断是否显示加载失败的空白页占位图
1 | enum MMStatusCode: Int { |
枚举 MMStatusCode 中除了 loadFail ,还有 cache,我们已经知道 loadFail 在数据加载失败的时候会出现,那 cache 是在什么时候出来呢?不急,看下一节就知道了。
数据缓存
一、基本使用
1 | // 缓存 |
缓存成功会返回一个 Bool 值,这里可不接收
| XXX 所支持类型 | |
|---|---|
| Bool | - |
| Float | - |
| Double | - |
| String | - |
| JSON | - |
| Modelable | [Modelable] |
| Moya.Response | - |
| Int | UInt |
| Int8 | UInt8 |
| Int16 | UInt16 |
| Int32 | UInt32 |
| Int64 | UInt64 |
其中,除了
Moya.Response之外,其它类型皆是通过JSON来实现缓存
所以,如果你想清除这些类型的缓存,只需要调用如下方法即可
1 |
|
清除 Moya.Response 则使用如下两个方法
1 |
|
再来看看MMCache.CacheContainer
1 | enum CacheContainer { |
这两种容器互不相通,即 即使key相同,使用
hybrid来缓存后,再通过RAM取值是取不到的。
- RAM : 仅缓存于内存之中,缓存的数据在APP使用期间一直存在
- hybrid :缓存于内存与磁盘中,APP重启后也可以获取到数据
二、缓存网络请求
内部缓存过程:
- APP首次启动并进行网络请求,网络数据将缓存起来
- APP再次启动并进行网络请求时,会先返回缓存的数据,等请求成功后再返回网络数据
- 其它情况只会加载网络数据
- 每次成功请求到数据后,都会对缓存的数据进行更新
1 | // Normal |
实际上是对
Moya请求后的Response进行缓存。 其实与Moya自带的方法相比较只多了一个参数cacheType: MMCache.CacheKeyType,定义着缓存中的key,默认为default
下面是 MMCache.CacheKeyType 的定义
1 | /** |
如果你想缓存
多页列表数据的最新一页数据,此时使用default是不合适的,因为default使用的key包含了pageIndex,这样就达不到只缓存最新一页数据的目的, 所以这里应该使用base或者custom(String)
我们可以来试一下带缓存的请求
1 | /* |
打印结果
1 | // 首次使用APP |
这里的 230 就是 MMStatusCode.cache.rawValue
CocoaPods
- 默认安装
MoyaMapper默认只安装Core下的文件
1 | pod 'MoyaMapper' |
RxSwift拓展
ruby1
pod 'MoyaMapper/Rx'
缓存拓展
ruby1
pod 'MoyaMapper/MMCache'
Rx缓存
ruby1
pod 'MoyaMapper/RxCache'




