RxSwift+Moya之网络请求

2021-05-13  本文已影响0人  iOS_我更专业

一、认识

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)都会使代码减少很多,业务层的代码也能更好的在链式响应式编程中得以体现...

未完待续~

上一篇下一篇

猜你喜欢

热点阅读