当前位置: 首页>编程语言>正文

Moya+RxSwift+HandyJson 实现网络请求及模型转换

Moya架构图

Moya+RxSwift+HandyJson 实现网络请求及模型转换,第1张
Moya架构图

CocoaPods集成

pod 'RxCocoa'
pod 'RxSwift'

pod 'Moya/RxSwift'
pod 'HandyJSON'

Moya简单使用

1.定义枚举,存储网络请求
// 定义一个枚举,存放我们的网络请求
enum MemberApi {
    case login(username:String,password:String,token:String)
}
2. 实现moya的TargetType协议
extension MemberApi:TargetType{

    //api 接口基地址
    var baseURL: URL {
        return URL.init(string: BaseURL)!
    }

    //请求路径
    var path:String{
        switch self {
        case .login(username: _, password:_ , token:_):
            return "login/accountLogin"
        }
    }


    var headers: [String: String]{
        return nil;
    }

    //请求的参数
    var parameters: [String: Any]{
        switch self {
        case .login(username: let userName, password: let pwd, token: let token):
            return ["account":userName,"pwd":pwd,"deviceToken":token];
        }
    }


    ///请求方式
    var method: Moya.Method {
        switch self {
        case .login(username: _, password: _, token: _):
        return .post;
        }
    }

    /// The method used for parameter encoding.
    var parameterEncoding: ParameterEncoding {
        return URLEncoding.default
    }

    /// Provides stub data for use in testing.
    var sampleData: Data {
        return "".data(using: String.Encoding.utf8)!
    }

    //MARK:task type
    var task: Task {
       return .requestPlain
    }

    var validate: Bool {
        return false
    }

}
3. 发起网络请求
let provider = MoyaProvider<MemberApi>();

provider.request(.login(username: "haha", password: "123456", token: "qwe")) { (result) in
     if result.error == nil{
         LLog(result.value);
     }
}

模型转换

首先, 我们需要处理Moya请求返回Moya.Response对象, 在返回给客户端时我们需要将Moya.Response映射成相应的模型对象。
其次, 我们希望使用RxSwift的链式写法来完成字典到模型的转换。

基于如上两点: 我们需要做如下两步处理。
1.扩展RxSwift 的 Observable 协议给其添加mapModel方法,传入要映射的模型类型
2.需要将Moya.Response对象映射成相应的模型对象,这里配合使用HandyJSON库

代码如下:

///定义在处理过程中可能出现的Error
enum RxSwiftMoyaError: String {
    case ParseJSONError   ///解析json时出错
    case OtherError       ///其他错误  
    case ResponseError    ///返回的结果有错
    case RequestFailedError ///请求返回错误 (根据请求码判断)
}

///让其实现Swift.Error 协议
extension RxSwiftMoyaError: Swift.Error { }


///扩展 RxSwift的Observable协议,添加mapModel方法
extension Observable {

    func mapModel<T: HandyJSON>(_ type: T.Type) throws -> Observable<T> {
        return map { response in

            ///判断Response类型
            guard let response = response asMoya.Response else {
                throw RxSwiftMoyaError.ResponseError
            }
            
            ///判断请求码
            guard (200...209) ~= response.statusCode else {
                throw RxSwiftMoyaError.RequestFailedError
            }
            
            ///转json
            guard let json = tryJSONSerialization.jsonObject(with: response.data, options: JSONSerialization.ReadingOptions.init(rawValue: 0)) as! [String: Any] else {
                throw RxSwiftMoyaError.ResponseError
            }
            

            ///使用HandyJSON库,映射成指定模型
            let object = JSONDeserializer<T>.deserializeFrom(dict: json)
            guard let model = object else {
                throw RxSwiftMoyaError.ParseJSONError
            }
            return model
        }
    }
}

使用:

///初始化一个MoyaProvider, 其中MemberApi为使用了TargetType协议的enum枚举
let mp = MoyaProvider<MemeberApi>()
let ob = mp
.rx.request(type)  /// rx.request 为Moya/RxSwift 库中提供的扩展实现,返回的是一个Single类型
.asObservable()  ///需要使用asObservable将Single类型转成Observable
.mapModel(UserInfo.self) ///将请求返回结果进行映射

网络请求的处理过程大致如上,代码中只有有网络请求的地方就会有如下代码,所以这块代码的调用我们再把它封装一下。

final class NetworkTools {
    
    static func request<H: HandyJSON, T: TargetType>(_ type:T, _ model: H.Type) -> Observable<H> {
        
        let mp = MoyaProvider<T>()

        let ob = mp
            .rx.request(type)  ///type 实现T类型协议的具体对象
            .asObservable()
            .mapModel(model)
        
        return ob
    }
}


///使用
NetworkTools.request(MemberApi.login(username: "haha", password: "123456", token: "qwe"), UserInfo.self)
.subscribe(onNext:{   ///订阅
    
})

最后

针对网络层的封装,在如下的Demo中又做了演进,如果感兴趣,请移步至项目 TestProject 中查看


https://www.xamrdz.com/lan/5s82016200.html

相关文章: