淺談RxSwift 網(wǎng)絡請求
一、說明
入坑RxSwift 有段時間了,之前在項目中只是小范圍的使用RxSwift,為了更好的使用響應式編程,決定在項目中更廣范圍的使用RxSwift,然后研究了一下RxSwift的網(wǎng)絡請求,現(xiàn)在有關網(wǎng)絡請求的案例大多是基于RXSwift(4.0.0)或者更早的庫來寫的,本篇文章是基于目前最新的版本(4.2.0)版本來寫的,由于RxSwift 版本的更新,里面的使用語法,發(fā)生了變化,在整理的過程中遇到了一些問題,為了讓后來學習的小伙伴,節(jié)約時間,決定記錄下來
二、網(wǎng)絡請求
1.使用RxSwift相關庫的版本
- ObjectMapper (3.2.0)
- HandyJSON (4.1.1)
- Moya (11.0.2)
- RxCocoa (4.2.0)
- RxSwift (4.2.0)
2.在Swift語言中,我們使用Alamofire 作為網(wǎng)絡庫,moya 是對Alamofire 更抽象一層的封裝,RxSwift把Moya封裝后作為網(wǎng)絡請求的接口,我們在使用的時候只需要實現(xiàn) TargetType 協(xié)議就好,用一個例子來看下怎么使用:
import Foundation
import Moya
enum 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 ,作用主要是在內部定義網(wǎng)絡請求的接口,然后,就是對協(xié)議 TargetType進行擴展,我們一一解讀下里面的參數(shù)
- baseURL:網(wǎng)絡請求的基本URL
- path:用于匹配具體網(wǎng)絡請求接口
- method:網(wǎng)絡請求方式,常用就是 get/post 兩種
- parameters:接口請求時要帶的參數(shù)
- parameterEncoding:參數(shù)編碼方式(這里使用URL的默認方式)
- sampleData:這里用于單元測試
- task:執(zhí)行網(wǎng)絡請求的任務
- validationType:是否執(zhí)行Alamofire驗證,默認值為false
- headers:網(wǎng)絡請求時需要的header,如果和后臺沒有特殊的驗證處理,默認傳nil 就可以
- APIService 作為網(wǎng)絡請求的統(tǒng)一接口,里面封裝了網(wǎng)絡請求所需的一些基本數(shù)據(jù)
3.在進行網(wǎng)絡請求之前,需要做一些準備工作,把網(wǎng)絡請求回的數(shù)據(jù)通過JSON 轉化成 Model , 這里我們使用了兩種方式進行轉換(根據(jù)項目的情況,靈活選擇使用),一種通過 ObjectMapper庫進行轉換,一種是通過 HandyJSON 庫 進行轉換 ,分別通過對 Response 類 擴展 ,以下是對這兩種方式的封裝
其一:使用 ObjectMapper庫 把JSON 轉換成 Model
import Foundation
import RxSwift
import Moya
import ObjectMapper
// MARK: - Json -> Model
extension 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 Foundation
import RxSwift
import Moya
import HandyJSON
extension 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中,使用已經封裝好的接口進行網(wǎng)絡請求,代碼如下:
import RxSwift
import Moya
import ObjectMapper
import HandyJSON
import RxCocoa
class MainClassViewModel {
private let provider = MoyaProvider<APIService>()
let disposeBag = DisposeBag()
var dataSource = BehaviorRelay<[MainClassModelMapObject_sub]>(value:[])
var networkError = BehaviorRelay(value: Error.self)
}
//MARK: -- 網(wǎng)絡
extension MainClassViewModel {
//網(wǎng)絡請求-- ObjectMapper
func getClassListWithMapObject(){
provider.rx.request(.mainClassList).asObservable().mapObjectModel(MainClassModelMapObject.self).subscribe({ [unowned self] (event) in
switch event {
case let .next(classModel):
print("ObjectMapper -- 加載網(wǎng)絡成功")
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)
}
//網(wǎng)絡請求-- HandyJSON
func getClassListWithMapHandyJson(){
provider.rx.request(.mainClassList).asObservable().mapHandyJsonModel(MainClassModel.self).subscribe({ [unowned self] (event) in
switch event {
case let .next(classModel):
print("HandyJSON -- 加載網(wǎng)絡成功")
case let .error( error):
print("error:", error)
self.networkError.accept(error as! Error.Protocol)
case .completed: break
}
}).disposed(by: self.disposeBag)
}
}
這里用了兩種方式,分別對 mainClassList API 接口進行了網(wǎng)絡請求,唯一不同的是,在得到到網(wǎng)絡請求回來數(shù)據(jù)的時候,一個是使用 mapObjectModel 把JSON 轉化成 Model ,一個是使用 mapHandyJsonModel 把 JSON轉化成Model ,由于我們使用的是不同的庫,把JSON 轉化成 Model,這兩種實現(xiàn)的方式還是有一些差別,下面是這兩種 Model 的具體實現(xiàn)方式:
其一、實現(xiàn)協(xié)議 Mappable
import UIKit
import ObjectMapper
class 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"]
}
}
其二、實現(xiàn)協(xié)議 HandyJSON
import UIKit
import HandyJSON
struct 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 進行網(wǎng)絡請求的分析,接下來看一個示例如何使用,在MainClassViewModel 中我們使用 dataSource 保存了網(wǎng)絡請求回來的數(shù)據(jù),我們要在 ViewController里 用tableview 把這個數(shù)據(jù)展示出來,需要提前把數(shù)據(jù)源和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 網(wǎng)絡請求的相關知識,下面是一個寫好的demo
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
iOS實現(xiàn)設備判斷是否安裝相關地圖(百度、高德等)
這篇文章主要給大家介紹了關于iOS如何實現(xiàn)設備判斷是否安裝相關地圖,比如百度、高德等,其實實現(xiàn)的方法還是很簡單,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友下面來一起看看吧。2018-01-01
iOS 數(shù)據(jù)結構之數(shù)組的操作方法
這篇文章主要介紹了iOS 數(shù)據(jù)結構之數(shù)組的操作方法,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧2018-07-07
iOS移動端(H5)alert/confirm提示信息去除網(wǎng)址(URL)
這篇文章主要介紹了iOS移動端(H5)alert/confirm提示信息去除網(wǎng)址URL,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11
iOS UISegmentControl實現(xiàn)自定義分欄效果
這篇文章主要為大家詳細介紹了iOS UISegmentControl實現(xiàn)自定義分欄效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03

