RxSwift+Moya之网络请求
一、认识
RxSwift:函数式响应编程的框架
Moya :是一个基于 Alamofire 的更高层网络请求封装抽象层
二、实践
1、创建API枚举类:
enum API {
///检查版本
case checkVersion(nowVer:String)
}
API需要遵从 TargetType 的协议,且需要实现的方法如下:
//服务器地址
var baseURL:URL{}
//各个请求的具体路径
varpath:String{}
//请求任务事件(这里附带上参数)
var task:Task{}
//请求类型
var method:Moya.Method{}
//做单元测试模拟的数据
var sampleData: Data {}
//请求头
var headers: [String:String]? {}
2、Moya的扩展
extension PrimitiveSequence where Trait == SingleTrait, Element == Response {
/// 序列化成遵守Codeable协议的对象
///
/// - Parameter type: 需要序列化Data的类型
/// - Returns: 返回RxSwift的Signle类型
func map(_type:D.Type) ->Single {
return flatMap{ response ->Singlein
do{
let successfulResponse = try response.filterSuccessfulStatusCodes()
let model =tryJSONDecoder().decode(D.self, from: successfulResponse.data)
return Single.just(model)
}catch{
throw MoyaError.underlying(error, response)
}
}
}
}
extension PrimitiveSequence where Trait == SingleTrait, Element: Codable & TestResponse {
/// 验证接口返回的code是否为指定的值(默认为0)
func validate(code:Int=0) ->Single {
return flatMap{ response ->Singlein
guard response.Code==nilelse{
throw MoyaError.underlying(NSError(domain:"com.Abitofcomedy.error",
code:-1,
userInfo: [NSLocalizedDescriptionKey: response.Message??"未知错误"]),
nil)
}
returnSingle.just(response.data)
}
}
}
3、Base Model类
protocol TestResponse {
associatedtype ResponseDataType
var Code:Int? {get}
var Message:String? {get}
var data: ResponseDataType? { get }
}
struct TestModel<T: Codable>: Codable, TestResponse {
typealias ResponseDataType = T
let Code:Int?
let Message:String?
let data:T?
}
4、请求Manager类
class APIManager: MoyaProvider<API> {
static let shared=APIManager()
private init() {
let requestClosure = { (endpoint:Endpoint, closure:@escaping MoyaProvider.RequestResultClosure) in
do{
var urlRequest =try endpoint.urlRequest()
urlRequest.timeoutInterval=20
closure(.success(urlRequest))
}catchMoyaError.requestMapping(let url) {
closure(.failure(MoyaError.requestMapping(url)))
}catch MoyaError.parameterEncoding(let error) {
closure(.failure(MoyaError.parameterEncoding(error)))
}catch{
closure(.failure(MoyaError.underlying(error,nil)))
}
}
let networkLoggerPlugin =NetworkLoggerPlugin(configuration: .init(formatter: .init(entry: { (_identifier:String,_message:String,_target:TargetType) ->String in
return message
}, requestData: { (data) -> (String) in
if let string =String(data: data, encoding: .utf8) {
return "\n\n \(string.replacingOccurrences(of:"&", with:"\n "))\n"
}else{
return "请求信息解析错误"
}
}, responseData: { (data) -> (String)in
if let string =String(data: data, encoding: .utf8) {
return "\n\n \(string.replacingOccurrences(of:"&", with:"\n "))\n"
}else{
return "返回信息解析错误"
}
}), output: { (_target:TargetType, stringArr)in
}, logOptions: .verbose))
super.init(requestClosure: requestClosure, plugins: [networkLoggerPlugin])
}
}
5、请求
let disposeBag = DisposeBag()
APIManager.shared.rx
.request(.checkVersion(nowVer:"1.0.0"))
.map(TestModel<CheckVersionModel>.self)
.validate()
.subscribe(onSuccess: { (model)in
//成功获取 CheckVersionModel
//注:CheckVersionModel 继承 Codable 即可
}, onError: { (error)in
//失败
})
.disposed(by:disposeBag)
三、总结
这样对于请求的封装可能有一些深,但是这样代码的抽离,在Controller层(MVC)或者ViewModel层(MVVM)都会使代码减少很多,业务层的代码也能更好的在链式响应式编程中得以体现...
未完待续~