一、說明
入坑RxSwift 有段時間了,之前在項目中只是小范圍的使用RxSwift,為了更好的使用響應式編程,決定在項目中更廣范圍的使用RxSwift,然后研究了一下RxSwift的網絡請求,現在有關網絡請求的案例大多是基于RXSwift(4.0.0)或者更早的庫來寫的,本篇文章是基于目前最新的版本(4.2.0)版本來寫的,由于RxSwift 版本的更新,里面的使用語法,發生了變化,在整理的過程中遇到了一些問題,為了讓后來學習的小伙伴,節約時間,決定記錄下來
二、網絡請求
1.使用RxSwift相關庫的版本
2.在Swift語言中,我們使用Alamofire 作為網絡庫,moya 是對Alamofire 更抽象一層的封裝,RxSwift把Moya封裝后作為網絡請求的接口,我們在使用的時候只需要實現 TargetType 協議就好,用一個例子來看下怎么使用:
import Foundationimport Moyaenum APIService{ case mainClassList}extension APIService:TargetType{ var baseURL: URL { return URL(string:"http://cmsadmin.fotoable.net")! } var path: String { switch self { case .mainClassList: return "/sandboxColor/category" } } var method: Moya.Method { switch self { case .mainClassList: return .get } } var parameters: [String : Any]? { switch self { case .mainClassList: return nil } } var parameterEncoding: ParameterEncoding { return URLEncoding.default } var sampleData: Data { return "{}".data(using: String.Encoding.utf8)! } var task: Task { return .requestPlain } var headers: [String : String]? { return nil }}
首先,我們定義了一個 枚舉 APIService ,作用主要是在內部定義網絡請求的接口,然后,就是對協議 TargetType進行擴展,我們一一解讀下里面的參數
3.在進行網絡請求之前,需要做一些準備工作,把網絡請求回的數據通過JSON 轉化成 Model , 這里我們使用了兩種方式進行轉換(根據項目的情況,靈活選擇使用),一種通過 ObjectMapper庫進行轉換,一種是通過 HandyJSON 庫 進行轉換 ,分別通過對 Response 類 擴展 ,以下是對這兩種方式的封裝
其一:使用 ObjectMapper庫 把JSON 轉換成 Model
import Foundationimport RxSwiftimport Moyaimport ObjectMapper// MARK: - Json -> Modelextension Response { func mapObjectModel<T: BaseMappable>(_ type: T.Type, context: MapContext? = nil) throws -> T { guard let object = Mapper<T>(context: context).map(JSONObject: try mapJSON()) else { throw MoyaError.jsonMapping(self) } return object } func mapObjectArray<T: BaseMappable>(_ type: T.Type, context: MapContext? = nil) throws -> [T] { guard let array = try mapJSON() as? [[String : Any]] else { throw MoyaError.jsonMapping(self) } return Mapper<T>(context: context).mapArray(JSONArray: array) }}// MARK: - Json -> Observable<Model>extension ObservableType where E == Response { // 將Json解析為Observable<Model> public func mapObjectModel<T: BaseMappable>(_ type: T.Type) -> Observable<T> { return flatMap { response -> Observable<T> in return Observable.just(try response.mapObjectModel(T.self)) } } // 將Json解析為Observable<[Model]> public func mapObjectArray<T: BaseMappable>(_ type: T.Type) -> Observable<[T]> { return flatMap { response -> Observable<[T]> in return Observable.just(try response.mapObjectArray(T.self)) } }}
其二 : 使用 HandyJSON 庫 把JSON 轉化成 Model
import Foundationimport RxSwiftimport Moyaimport HandyJSONextension ObservableType where E == Response { public func mapHandyJsonModel<T: HandyJSON>(_ type: T.Type) -> Observable<T> { return flatMap { response -> Observable<T> in return Observable.just(response.mapHandyJsonModel(T.self)) } }}extension Response { func mapHandyJsonModel<T: HandyJSON>(_ type: T.Type) -> T { let jsonString = String.init(data: data, encoding: .utf8) if let modelT = JSONDeserializer<T>.deserializeFrom(json: jsonString) { return modelT } return JSONDeserializer<T>.deserializeFrom(json: "{/"msg/":/"請求有誤/"}")! }}
4.在MainClassViewModel中,使用已經封裝好的接口進行網絡請求,代碼如下:
import RxSwiftimport Moyaimport ObjectMapperimport HandyJSONimport RxCocoaclass MainClassViewModel { private let provider = MoyaProvider<APIService>() let disposeBag = DisposeBag() var dataSource = BehaviorRelay<[MainClassModelMapObject_sub]>(value:[]) var networkError = BehaviorRelay(value: Error.self)}//MARK: -- 網絡extension MainClassViewModel { //網絡請求-- ObjectMapper func getClassListWithMapObject(){ provider.rx.request(.mainClassList).asObservable().mapObjectModel(MainClassModelMapObject.self).subscribe({ [unowned self] (event) in switch event { case let .next(classModel): print("ObjectMapper -- 加載網絡成功") self.dataSource.accept(classModel.data) case let .error( error): print("error:", error) self.networkError.accept(error as! Error.Protocol) case .completed: break } }).disposed(by: self.disposeBag) } //網絡請求-- HandyJSON func getClassListWithMapHandyJson(){ provider.rx.request(.mainClassList).asObservable().mapHandyJsonModel(MainClassModel.self).subscribe({ [unowned self] (event) in switch event { case let .next(classModel): print("HandyJSON -- 加載網絡成功") case let .error( error): print("error:", error) self.networkError.accept(error as! Error.Protocol) case .completed: break } }).disposed(by: self.disposeBag) } }
這里用了兩種方式,分別對 mainClassList API 接口進行了網絡請求,唯一不同的是,在得到到網絡請求回來數據的時候,一個是使用 mapObjectModel 把JSON 轉化成 Model ,一個是使用 mapHandyJsonModel 把 JSON轉化成Model ,由于我們使用的是不同的庫,把JSON 轉化成 Model,這兩種實現的方式還是有一些差別,下面是這兩種 Model 的具體實現方式:
其一、實現協議 Mappable
import UIKitimport ObjectMapperclass MainClassModelMapObject: Mappable { var code:NSInteger? var data:[MainClassModelMapObject_sub]! required init?(map: Map) {} func mapping(map: Map) { code <- map["code"] data <- map["data"] }}class MainClassModelMapObject_sub: Mappable { var ID:String? var name:String? var desc:String? var imgUrl:String? var gifUrl:String? var isUpdate:Bool? var backgroundGroup:NSInteger? required init?(map: Map) {} func mapping(map: Map) { ID <- map["ID"] name <- map["name"] desc <- map["desc"] imgUrl <- map["imgUrl"] gifUrl <- map["gifUrl"] isUpdate <- map["isUpdate"] backgroundGroup <- map["backgroundGroup"] }}
其二、實現協議 HandyJSON
import UIKitimport HandyJSONstruct MainClassModel: HandyJSON { var code:NSInteger? var data:[MainClassModel_sub]!}struct MainClassModel_sub: HandyJSON { var ID:String? var name:String? var desc:String? var imgUrl:String? var gifUrl:String? var isUpdate:Bool? var backgroundGroup:NSInteger?}
5、以上是使用 RxSwift 進行網絡請求的分析,接下來看一個示例如何使用,在MainClassViewModel 中我們使用 dataSource 保存了網絡請求回來的數據,我們要在 ViewController里 用tableview 把這個數據展示出來,需要提前把數據源和TableView進行綁定,以下是示例代碼:
//cell viewModel.dataSource.bind(to: tableView.rx.items) { (tableView, row, element) in let cell = tableView.dequeueReusableCell(withIdentifier: "MainClassTableViewCell", for: IndexPath(row: row, section: 0)) as! MainClassTableViewCell cell.setModel(model: element) // configure cell return cell } .disposed(by: disposeBag)
在需要使用的地方,調用 方法 getClassListWithMapObject() 或者 getClassListWithMapHandyJson()
三、總結
這部分的內容,適合對RxSwift 有一定了解的小伙伴學習, 文章重點是 幫助大家學習和了解 RxSwift 網絡請求的相關知識,下面是一個寫好的demo
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。
新聞熱點
疑難解答