RxSwift學(xué)習(xí)-- 網(wǎng)絡(luò)層的搭建

我們平常的網(wǎng)絡(luò)請求基本步驟
1 發(fā)送Request
2 接受 Response
3 json轉(zhuǎn)model (我目前是有這一步的)

1 不利用三方框架的Rx網(wǎng)絡(luò)層

在實(shí)際生產(chǎn)過程中,我們都會使用第三方的網(wǎng)絡(luò)框架。但為了學(xué)習(xí)基本流程,我們最好還是實(shí)現(xiàn)自己的一套簡易框架。

1.1 對URLSession 進(jìn)行Rx擴(kuò)展,讓他用它Rx的功能

創(chuàng)建URLSession+Rx文件

func response(request: URLRequest) -> Observable<(HTTPURLResponse, Data)> {
        return Observable.create { observable in
            let task = self.base.dataTask(with: request) { (data, response, error) in
                //處理數(shù)據(jù)
                if let error = error {
                    observable.onError(error)
                    return
                }

                observable.onNext((response as! HTTPURLResponse, data!))
                observable.onCompleted()
            }
            task.resume()
            return Disposables.create(with: task.cancel)
        }
    }

我們拆分來看一下

func response(request: URLRequest) -> Observable<(HTTPURLResponse, Data)> {
        return Observable.create { observable in
      //請求
            return Disposables.create()
        }
    }

這幾乎是rx擴(kuò)展的基本樣式,中間加上URLSesson的請求 和 請求之后發(fā)送 錯誤 或者完成信號就可以了。
我們來看一下成果

let request = URLRequest.init(url: URL.init(string: "")!)
let response = URLSession.shared.rx.response(request: request)

response.subscribe(onNext: { (response, data) in
            //數(shù)據(jù)處理
 }).addDisposableTo(bag)

數(shù)據(jù)處理這部分也挺惡心了,也應(yīng)該封裝起來
通常數(shù)據(jù)處理 我們先處理data -> json ,之后json ->model. 事實(shí)上 不是所有的VC需要的數(shù)據(jù)都是model.所以 我們要暴露json 和model 2個接口。供調(diào)用者選用

在處理數(shù)據(jù)之前要確定數(shù)據(jù)是否有效,根據(jù)返回的狀態(tài)碼來判斷,
篩選出正常返回的數(shù)據(jù)

func data(request: URLRequest) -> Observable<Data> {
        return response(request: request).map { (response, data) in
            if 200..<300 ~= response.statusCode {
                return data
            } else {
                throw URLSessionError.failed
            }

        }
    }

json

func json(request: URLRequest) -> Observable<[String: Any]> {
        return data(request: request).map{ data  in
            let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]

            return json!
        }
    }

model
轉(zhuǎn)化model 這一步 這里我沒有自己用原生實(shí)現(xiàn),Swift不支持運(yùn)行時(不包含繼承NSObject的類)這里偷偷的用一下三方吧ObjectMapper(用法 后面介紹)

func model<T: Mappable>(request: URLRequest, model: T.Type) -> Observable<T> {
        return json(request: request).map{ json in
            let object = Mapper<T>().map(JSONObject: json["data"])
            return object!
        }
    }

這里的轉(zhuǎn)model 在實(shí)際情況下會出現(xiàn)許多問題。舉個例子
商品列表 商品詳情
商品詳情是單純的model
商品列表是 model的數(shù)組,所以根據(jù)不同情況可能還需要一個ModelArray的方法。和model的一樣,就不在重復(fù)了。
我們到VM中看看我們的戰(zhàn)果

let request = URLRequest.init(url: URL.init(string: "")!)
let response = URLSession.shared.rx.model(request: request, model: GoodsDetailModel.self)

response.subscribe(onNext: { model in
            //數(shù)據(jù)處理
        }).addDisposableTo(bag)

這樣我們一個基本的rx 的網(wǎng)絡(luò)層基本完成了。如果要使用可以放在一個NetWorkingService類 。避免于vm大量的耦合。具體封裝方法 就看大家的想法啦。是集約型 還是 分散型,都看自己的喜好了

2 RxMoya

在生產(chǎn)中,強(qiáng)烈推薦RxMoya真的大而全。
這邊我們簡單的介紹使用方法
首先確定配置文件創(chuàng)建XXAPI.Swift
我隨便寫一個了

enum GoodsAPI {
    case goodsDetail(goodsID: String)
}

extension GoodsAPI: TargetType {
    var parameterEncoding: ParameterEncoding {
        return URLEncoding.default
    }

    var task: Task {
        return .request
    }

    var path: String {
        return ""
    }

    var base: String {
        return ""
    }

    var baseURL: URL {
        return URL.init(string: base)!
    }

    var parameters: [String: Any]? {
        switch self {
        case .goodsDetail(let id):
            return []
        default:
            return nil
        }
    }

    var method: Moya.Method {
        return .post
    }

    var sampleData: Data {
        return "".data(using: .utf8)!
    }



}

遵循TargetType 實(shí)現(xiàn)基本配置
然后在VM中調(diào)用

let service = RxMoyaProvider<GoodsAPI>()

    var goodsDetailModel: Observable<GoodsDetailModel> {
        return self.service.request(.goodsDetail(goodsID: "10133")).mapObject(GoodsDetailModel.self)
    }

這樣就可以讓VM中的model暴露給VC使用了。簡單方便

=========
介紹下ObjectMapper的使用
1 遵循 Mappable協(xié)議
2 實(shí)現(xiàn)協(xié)議方法 init 和 mapping
這里的mapping 一定要寫映射關(guān)系,畢竟沒有運(yùn)行時這種東西了。
注意的是如果返回的Int類型,你用String 是無法接受的(很難受)

struct GoodsDetailModel: Mappable {
    var goodsID: Int?
    var goodsInfo: String?
    var goodsName: String?
    var introduction: String?
    var label: String?
    var tag: String?
    var goodsPic: String?
    var xPrice: String?
    var yPrice: String?
    var number: Int?
    var batchNO: String?
    var activityGoods: Bool?

    init?(map: Map) {

    }

    mutating func mapping(map: Map) {
        goodsID <- map["goodsID"]
        goodsInfo <- map["goodsInfo"]
        goodsName <- map["goodsName"]
        introduction <- map["introduction"]
        label <- map["label"]
        tag <- map["tag"]
        goodsPic <- map["goodsPic"]
        xPrice <- map["xPrice"]
        yPrice <- map["yPrice"]
        number <- map["number"]
        batchNO <- map["batchNO"]
        activityGoods <- map["activityGoods"]
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容