美文网首页
RXSwift基础网络请求封装

RXSwift基础网络请求封装

作者: iOS小乔 | 来源:发表于2018-08-10 13:56 被阅读442次

    一、创建项目,集成cocoapods文件

    target 'TestAPI' do
        use_frameworks!
    
        pod 'Alamofire'
        pod 'SwiftyJSON'
        pod 'RxSwift',    '~>4.1.1'
        pod 'RxCocoa',    '~>4.1.1'
        pod 'RxDataSources'
        pod 'Moya/RxSwift', '~> 11.0'
        pod 'NSObject+Rx'
        pod 'SVProgressHUD'
    end
    

    这里使用的是Moya、SwiftyJSON、Alamofire进行网络请求的封装。

    二、配置网络请求

    //1、根据Moya要求,网络请求需要创建一个Provider,MoyaProvider需要我们传入一个实现TargetType协议的对象,这个协议里面包含了请求的路由地址和具体路径、请求方式等网络请求相关基本信息
    let ComSmaManProvider = MoyaProvider<ComSmaManApi>(plugins:[AuthPlugin()])
    //路由地址
    let KBaseURL = "https://www.douban.com"
    
    public enum ComSmaManApi{
          //基本路由地址get、post请求
          case post(suffixUrl:String, params:[String:Any])
          case get(suffixUrl:String, params:[String:Any])
    
          //其它路由地址get、post请求
          case otherRequst(baseUrl:String, type:OtherBaseURLRequst)
          public enum OtherBaseURLRequst {
                case post(suffixUrl:String, params:[String:Any])
                case get(suffixUrl:String, params:[String:Any])
          }
    
    }
    //实现TargetType协议,配置基本信息
    extension ComSmaManApi:TargetType{
        //路由地址
        public var baseURL: URL {
              let result = self.getConfigure()
              return URL(string: result.1)!
        }
        //具体地址
        public var path: String {
              let result = self.getConfigure()
              return result.2
        }
        //请求方式get、post
        public var method: Moya.Method {
              let result = self.getConfigure()
              return result.0
        }
        //单元测试所用
        public var sampleData: Data {
              return "{}".data(using: .utf8)!
        }
        //请求任务事件(这里附带上参数)
        public var task: Task {
            //request上传、upload上传、download下载
           let result = self.getConfigure()
           return .requestParameters(parameters: result.3, encoding: URLEncoding.default)
        }
        //请求头
        public var headers: [String : String]? {
            return nil
        }
    
        private func getConfigure() -> (Moya.Method,String,String,[String:Any]) {
            switch self {
            case .get(suffixUrl: let suffixUrl, params: let params):
                return (.get,KBaseURL,suffixUrl,params)
            case .post(suffixUrl: let suffixUrl, params: let params):
                return (.post,KBaseURL,suffixUrl,params)
            case .otherRequst(baseUrl: let baseUrl, type: let type):
                switch type{
                    case .get(suffixUrl: let suffixUrl, params: let params):
                          return (.get,baseUrl,suffixUrl,params)
                    case .post(suffixUrl: let suffixUrl, params: let params):
                          return (.post,baseUrl,suffixUrl,params)
                 }
            }
        }
    
    }
    //当需要在header里面添加请求token或者时间戳等信息时可以传入这些配置
    struct AuthPlugin: PluginType {
    
    func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
        /*
        var request = request
        UserDefaults.standard.synchronize()
        let accessToken = UserDefaults.standard.value(forKey: "accessToken") as? String
        let timestamp: Int = Int.getTimeStamp()
        request.addValue("\(timestamp)", forHTTPHeaderField: "timestamp")
        if accessToken != nil {
            request.addValue(accessToken!, forHTTPHeaderField: "accessToken")
        }
        print(request.allHTTPHeaderFields)
         */
        return request
    }
    }
    

    三、配合SwiftyJSONMapper实现Data转JSON,JSON转Model

    1、先创建一个JSONMappable协议,让我们创建的model都遵守这个协议
    Snip20180810_1.png
    2、对Response和PrimitiveSequence扩展
    Snip20180810_2.png

    Response+SwiftyJSONMapper文件

    public extension Response {
    
    /// Maps data received from the signal into an object which implements the ALSwiftyJSONAble protocol.
    /// If the conversion fails, the signal errors.
    public func map<T: JSONMappable>(to type:T.Type) throws -> T {
        let jsonObject = try mapJSON()
        
        guard let mappedObject = T(fromJson: JSON(jsonObject)) else {
            throw MoyaError.jsonMapping(self)
        }
        
        return mappedObject
    }
    
    /// Maps data received from the signal into an array of objects which implement the ALSwiftyJSONAble protocol
    /// If the conversion fails, the signal errors.
    public func map<T: JSONMappable>(to type:[T.Type]) throws -> [T] {
        let jsonObject = try mapJSON()
        
        let mappedArray = JSON(jsonObject)
        let mappedObjectsArray = mappedArray.arrayValue.flatMap { T(fromJson: $0) }
        
        return mappedObjectsArray
    }
    
    }
    
    extension Response {
    
    @available(*, unavailable, renamed: "map(to:)")
    public func mapObject<T: JSONMappable>(type:T.Type) throws -> T {
        return try map(to: type)
    }
    
    @available(*, unavailable, renamed: "map(to:)")
    public func mapArray<T: JSONMappable>(type:T.Type) throws -> [T] {
        return try map(to: [type])
    }
    }
    

    PrimitiveSequence+SwiftyJSONMapper文件

    /// Extension for processing Responses into Mappable objects through ObjectMapper
    extension PrimitiveSequence where TraitType == SingleTrait, ElementType == Response {
    
    /// Maps data received from the signal into an object which implements the ALSwiftyJSONAble protocol.
    /// If the conversion fails, the signal errors.
    public func map<T: JSONMappable>(to type: T.Type) -> Single<T> {
        return flatMap { response -> Single<T> in
            return Single.just(try response.map(to: type))
        }
    }
    
    /// Maps data received from the signal into an array of objects which implement the ALSwiftyJSONAble protocol.
    /// If the conversion fails, the signal errors.
    public func map<T: JSONMappable>(to type: [T.Type]) -> Single<[T]> {
        return flatMap { response -> Single<[T]> in
            return Single.just(try response.map(to: type))
        }
    }
    }
    
    3、创建model
    import SwiftyJSON
    struct Douban: JSONMappable{
    var channels :[Channel]?
    init(fromJson json: JSON) {
        channels = json["channels"].arrayValue.map({Channel(fromJson: $0)})
    }
    }
    
    struct Channel: JSONMappable {
    var name :String?
    var nameEn :String?
    var channelId :String?
    var seqId :String?
    var abbrEn :String?
    
    init(fromJson json: JSON) {
        name = json["name"].stringValue
        nameEn = json["nameEn"].stringValue
        channelId = json["channel_id"].stringValue
        seqId = json["seqId"].stringValue
        abbrEn = json["abbrEn"].stringValue
    }
    }
    
    struct Playlist:JSONMappable {
    
    var r :Int!
    var isShowQuickStart: Int!
    var song:[Song]!
    
    init(fromJson json: JSON) {
        r = json["r"].intValue
        isShowQuickStart = json["is_show_quick_start"].intValue
        song = json["song"].arrayValue.map({Song(fromJson: $0)})
    }
    
    }
    
    struct Song:JSONMappable {
    var title: String!
    var artist: String!
    init(fromJson json: JSON) {
        title = json["title"].stringValue
        artist = json["artist"].stringValue
    }
    }
    
    4、在viewcontroller中利用ComSmaManProvider请求数据
      let data = ComSmaManProvider.rx.request(.get(suffixUrl: "/j/app/radio/channels", params: [:]))
            .map(to: Douban.self)  //转换成model
            .map{$0.channels ?? []} //获取数组channels作为tableview的数据源
            .asObservable()
        //将数据绑定到tableview上
        data.bind(to: tableView.rx.items){ (tableView,row,element) in
            
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
            cell.textLabel?.text = element.name
            cell.accessoryType = .disclosureIndicator
            return cell
        }.disposed(by: disposeBag)
    
    5、最终效果
    Snip20180810_3.png

    四、在实际开发项目中,我们都与后台约定一个数据返回成功的标识,比如status为1是成功,0为失败等等其他状态。

    创建ResponseMapper文件,内容如下

    let RESULT_CODE = "status"
    let RESULT_DATA = "data"
    
    
    enum XYRequestStatus:String {
        case RequstSuccess = "200"
        case RequstError
    }
    
    
    enum XYError : Error {
        case noRepresentor
        case notSuccessfulHTTP
        case noData
        case couldNotMakeObjectError
        case bizError(resultCode: String?, resultMsg: String?)
    }
    
    
    extension Observable{
    
        private func resultFromJSON<T:JSONMappable>(jsonData:JSON,classType:T.Type) -> T? {
        return T(fromJson: jsonData)
    }
    
    func mapResponseToObj<T:JSONMappable>(type:T.Type) -> Observable<T?> {
        return map{ representor in
            guard let response = representor as? Moya.Response else{
                throw XYError.noRepresentor
            }
            guard ((200...209) ~= response.statusCode) else{
                throw XYError.notSuccessfulHTTP
            }
            
            let json = try? JSON.init(data: response.data)
            if let code = json?[RESULT_CODE].string{
                if code == XYRequestStatus.RequstSuccess.rawValue{
                    
                    return self.resultFromJSON(jsonData: json![RESULT_DATA], classType: type)
                } else {
                    
                    throw XYError.bizError(resultCode: json?["code"].string, resultMsg: json?["msg"].string)
                }
            }else{
                throw XYError.couldNotMakeObjectError
            }
        }
    }
    
    func mapResponseToObjArray<T:JSONMappable>(type:T.Type) -> Observable<[T]> {
        return map{ representor in
            guard let response = representor as? Moya.Response else{
                throw XYError.noRepresentor
            }
            guard ((200...209) ~= response.statusCode) else{
                throw XYError.notSuccessfulHTTP
            }
            
            let json = try? JSON.init(data: response.data)
            
            if let code = json?[RESULT_CODE].string{
                if code == XYRequestStatus.RequstSuccess.rawValue{
                    
                    var objects = [T]()
                    let objectsArray = json?[RESULT_DATA].array
                    if let array = objectsArray{
                        for object in array{
                            if let obj = self.resultFromJSON(jsonData: object, classType: type){
                                objects.append(obj)
                            }
                        }
                        return objects
                    }else{
                        throw  XYError.noData
                    }
                    
                }else{
                    throw XYError.bizError(resultCode: json?["code"].string, resultMsg: json?["msg"].string)
                }
                
            }else{
                throw XYError.couldNotMakeObjectError
            }
        }
    }
    
    }

    相关文章

      网友评论

          本文标题:RXSwift基础网络请求封装

          本文链接:https://www.haomeiwen.com/subject/ykqkbftx.html