Swift网络请求之Moya的使用

1,Alamofire网络框架请求数据
在iOS的工程中,之前用的是Alamofire网络框架,这个框架的一个网络请求示例如下:

func setUserStatus() {
    let parameters:[String : Any] = ["userid": userid!]
    Alamofire.request(URL_SET_USER_STATUS, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: nil).responseObject{[weak self]
        (response :DataResponse) in
        if self == nil{
            return
        }
        let ret = response.result.value
        if response.result.error != nil{
            ......
        }else{
            .......
        }
    }
}

每个接口都需要拼接这些信息,包括api路径,请求的方式,参数,参数编码格式,消息头等几个主要部分,获取到网络数据后,再解析数据进行处理。
2,moya
moya的中文说明:https://github.com/Moya/Moya/blob/master/Readme_CN.md
它对网络请求的url和parameter进行了更深的封装
TargetType这个是使用moya必须要实现的一个协议,这个里面我们基本可以看到它封装的主要内容

public protocol TargetType {

    /// The target's base `URL`.
    var baseURL: URL { get }

    /// The path to be appended to `baseURL` to form the full `URL`.
    var path: String { get }

    /// The HTTP method used in the request.
    var method: Moya.Method { get }

    /// Provides stub data for use in testing.这个数据是用在api测试时用的
    var sampleData: Data { get }

    /// The type of HTTP task to be performed.
    var task: Task { get }

    /// Whether or not to perform Alamofire validation. Defaults to `false`.
    var validate: Bool { get }

    /// The headers to be used in the request.
    var headers: [String: String]? { get }
}

3,moya的使用示例
基本的使用示例:https://github.com/Moya/Moya/blob/master/docs/Examples/Basic.md
同样的接口封装成moya后

//Moya 10的版本已经去掉了RxMoyaProvider代码,直接用MoyaProvider
let provider = MoyaProvider()
provider.rx.request(.setUserStatus)
            .asObservable().mapJSON()
            .mapObject(type: UserStatusModel.self)
            .subscribe { [weak self] event in
                if self == nil{
                    return
                }
                switch event {
                case let .next(response):
                    //............
                    break
                case let .error(error):
                    print(error)
                    //这个地方,处了网络异常外,对错误码也可处理
                    if let err = error as? NSError{
                        if err.domain == "Network"{
                            switch err.code{
                            case 401:
                            print("param invalide")
                            break
                            default:
                            print("other error")    
                            }
                        }else{
                            print("other error") 
                        }
                    }else{
                        print("other error") 
                    }
                    break
                default:
                    break
                }
            }.disposed(by: disposeBag)

4,ObjectMapper
获取到网络数据后,需要将json解析成对象数据,可配合ObjectMapper一起用。一般服务端返回的数据是

{
"code": 200,
"message": "",
"data": {}
}

这样我们可以对这些错误码进行统一处理,data数据解析成功后返回

import Foundation
import RxSwift
import ObjectMapper
import RxCocoa

extension Observable {
    func mapObject(type: T.Type) -> Observable {
        return self.map { response in
            //if response is a dictionary, then use ObjectMapper to map the dictionary
            //if not throw an error
            guard let dict = response as? [String: Any] else {
                throw RxSwiftMoyaError.ParseJSONError
            }
            guard (dict["code"] as? Int) != nil else{
                throw RxSwiftMoyaError.ParseJSONError
            }
            
            if let error = self.parseError(response: dict) {
                throw error
            }
            return Mapper().map(JSON: dict["data"] as! [String : Any])!
        }
    }
    
    func mapArray(type: T.Type) -> Observable<[T]> {
        return self.map { response in
            guard response is [Any] else {
                throw RxSwiftMoyaError.ParseJSONError
            }
            
            guard let dicts = response as? [String: Any] else {
                throw RxSwiftMoyaError.ParseJSONError
            }
            
            guard (dicts["code"] as?Int) != nil else{
                throw RxSwiftMoyaError.ParseJSONError
            }
            
            if let error = self.parseError(response: dicts) {
                throw error
            }
            
            return Mapper().mapArray(JSONArray: [dicts["data"] as! [String : Any]])
        }
    }
    
    func parseServerError() -> Observable {
        return self.map { (response) in
            let name = type(of: response)
            print(name)
            guard let dict = response as? [String: Any] else {
                throw RxSwiftMoyaError.ParseJSONError
            }
            if let error = self.parseError(response: dict) {
                throw error
            }
            return self as! Element
        }
        
    }
    
//最外层的dictionary解析,将data数据取去后转换成json对象
//如果是错误码,抛异常处理
    fileprivate func parseError(response: [String: Any]?) -> NSError? {
        var error: NSError?
        if let value = response {
            var code:Int?
            if let codes = value["code"] as? Int{
                code = codes
            }
            if  code != 200 {
                var msg = ""
                if let message = value["message"] as? String {
                    msg = message
                }
                error = NSError(domain: "Network", code: code!, userInfo: [NSLocalizedDescriptionKey: msg])
            }
        }
        return error
    }
}

enum RxSwiftMoyaError: String {
    case ParseJSONError
}

extension RxSwiftMoyaError: Error {
    
}

至此,rxswift + moya就可以正常使用了
当然,moya的相比alamofire还有很多好用的功能,后面再跟大家分享

参考文档:
http://www.jianshu.com/p/c1494681400b

你可能感兴趣的:(Swift网络请求之Moya的使用)