我們平常的網(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"]
}
}