Alamofire+RxSwift实现一个优雅的网络请求
在封装网络层的时候,首先瞥了一眼Alamofire,发现似乎一切都很不错并不用什么封装。。但是善于增加复杂度的我并不死心。于是就有了接下来的折(zhuang)腾(x)
为了响应swift面向协议编程的号召,在这里我定义了一个protocol,定义了请求路径,请求方式,参数,以及是否显示HUD
public protocol Request {
var path:String{get}
var method:HTTPMethod{get}
var parameters: [String:Any]? {get}
var hud:Bool{get}
}
得益于swift 3的花式语法,我们可以给这个protocol加一个默认实现。这样的好处就是负责实现这个协议的class,enum或是struc可以忽略协议扩展中已经实现的方法
extension Request{
var hud:Bool{
return false
}
var method:HTTPMethod{
return HTTPMethod.post
}
}
请求协议写完后,我们再来写一个请求方法,这里选择了struc作为NetworkClient
public struct NetworkClient{
static func send<T :Request>(_r:T) ->Observable<[String:Any]>
}
注意,这个方法里我们用了一波泛型,约束了参数r必须是实现了Requst协议
请求方法同时这个方法还返回了一个约束数据类型为字典的Observable(在RAC里是RACSingal)。在这里我们默认了接口的是标准RESTAPI。所以我们可以分别处理code,message,result。
这里再贴一下我对error的处理
这里我们定义了一个实现Error协议的CZSError定义了几个简易的error,以及show方法这样一个简易的网络请求框架就基本完成了。接下来我们以登陆作为🌰来看一下它是怎么工作的
首先新建一个LoginAPI.swift。在里面声明一个enum。里面有两个接口,登陆,获取短信验证码
enum LoginAPI {
case Login(mobile:String?, auth_code:String?)
case SmsCode(mobile:String?)
}
接下来我们让这个enum实现Request协议
看起来还不错,每一个请求都可以单独配置参数,请求地址,或是HUD,或者你能想到的任何东西!
ok,最后一步,发起请求,项目中使用的是MVVM架构,所以VC和ViewModel是双向绑定的
在viewmodel中LoginStatus,和signedIn的声明 viewModel简单说一下信号之间的转换。loginTap产生的是一个Observable<Void>信号,把这个信号转换成了由phoneTextField和codeTextField(Observable<String>)聚合所产生的信号,然后flatMap得到phone和code,同时需要return一个 Observable<LoginStatus>信号,但是我们的send函数返回的是Observable<[String:Any]>类型的信号,这里我们来一个map,把信号中的数据转成LoginStatus类型,同时也可以做一些额外的处理。
解释一下flatMap和map,前者是return的是一个信号,而后者则是return 信号中的数据。说人话。。如果把这个过程比作水在管道里流动的话,前者是换了一节管道,而后者则是换了管道中的水
最后,我们在controller中订阅这个信号,拿到处理好后的结果。
在viewController中订阅这个信号一切都是辣么的完美。不是吗