一般情况下,从业务方从API中请求JSON数据时,一般都会经过以下三步:
1 | --------1------------2---------- |
当然,大部分情况下,原始数据就是JSON,所以第一步基本上只是对接受数据的一个类型转换。一般在网络层中,由组件方提供1步骤,而业务方往往在网络组件的回调中提供步骤2。简单的转换逻辑明了了,接下来就可以试下用Moya实现步骤1,ObjectMapper实现步骤2。
在结合RxSwift+Moya+ObjectMapper三者之后,常规JSON数据的获取与解析变得更加精简。以近期编写的一个V2ex API为例,获取个人信息接口如下:
1 | func fetchMemberInfo(_ username: String? = V2exAppContext.shared.currentUsername, |
实现
那么,上述函数的内部是如何实现的呢?
首先说下Moya。Moya是针对网络的一层封装,并且Moya在较为后期的版本中,还提供了RxSwift以及ReactiveCocoa的接口。针对RxSwift,Moya提供了以下两个好用的扩展:
1 | open func request(_ token: Target) -> Observable<Response> |
前者用来请求原始数据,后者则将原始数据转化成json。当然,Moya还提供了其他Rx扩展,比如filterStatus
系列方法,这里就不展开了。
有了上面两个方法,业务方请求数据时,就可以这样调用:
1 | let V2exProvider = RxMoyaProvider<V2ex>() |
上面json
即为解析完成的JSON数据流。
得到JSON数据流之后,就可以执行步骤2了,这里选用的是ObjectMapper。ObjectMapper是一个Swift编写的模型<->JSON转换库,应用代码非常简单,只要模型遵守Mappable协议,并且实现对应的方法就可以了:->
1 | init?(map: Map) |
然后在模型中设置对应属性的值,这里以V2ex的Member为例:
1 | struct V2exMember: Mappable { |
可以看到,对于struct类型的模型,这种转换方式还是很优雅的。生成模型的话,也只需要很简单的代码就可以完成:
1 | Mapper<V2exMember>().map(JSONObject: $0) |
到这里为止,步骤2也完成了,接下就可以将步骤1、2连接起来:
1 | extension ObservableType where E == Response { |
mapObject
将原始数据转换成单个模型,而mapObjectArray
将原始数据转换成模型数组。使用Rx.flatMap是为了方便抛出错误,终止正常数据流的流动。
总的来说,这三者结合后写出来的代码给人一种畅快淋漓的感觉。不过在很多项目中,从后台获取的JSON也许不会那么规范,或者说层次分明,这样一来,需要处理的情况就复杂多了,对于上面的Rx扩展能否保持这个精简的体量还待观察。
文中提到的代码可以在这里这里找到。