服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - 浅谈RxSwift 网络请求

浅谈RxSwift 网络请求

2021-05-05 22:04hylccmh IOS

这篇文章主要介绍了浅谈RxSwift 网络请求,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

一、说明

入坑RxSwift 有段时间了,之前在项目中只是小范围的使用RxSwift,为了更好的使用响应式编程,决定在项目中更广范围的使用RxSwift,然后研究了一下RxSwift的网络请求,现在有关网络请求的案例大多是基于RXSwift(4.0.0)或者更早的库来写的,本篇文章是基于目前最新的版本(4.2.0)版本来写的,由于RxSwift 版本的更新,里面的使用语法,发生了变化,在整理的过程中遇到了一些问题,为了让后来学习的小伙伴,节约时间,决定记录下来

二、网络请求

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 作为网络库,moya 是对Alamofire 更抽象一层的封装,RxSwift把Moya封装后作为网络请求的接口,我们在使用的时候只需要实现 TargetType 协议就好,用一个例子来看下怎么使用:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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 ,作用主要是在内部定义网络请求的接口,然后,就是对协议 TargetType进行扩展,我们一一解读下里面的参数

  • baseURL:网络请求的基本URL
  • path:用于匹配具体网络请求接口
  • method:网络请求方式,常用就是 get/post 两种
  • parameters:接口请求时要带的参数
  • parameterEncoding:参数编码方式(这里使用URL的默认方式)
  • sampleData:这里用于单元测试
  • task:执行网络请求的任务
  • validationType:是否执行Alamofire验证,默认值为false
  • headers:网络请求时需要的header,如果和后台没有特殊的验证处理,默认传nil 就可以
  • APIService 作为网络请求的统一接口,里面封装了网络请求所需的一些基本数据

3.在进行网络请求之前,需要做一些准备工作,把网络请求回的数据通过JSON 转化成 Model , 这里我们使用了两种方式进行转换(根据项目的情况,灵活选择使用),一种通过 ObjectMapper库进行转换,一种是通过 HandyJSON 库 进行转换 ,分别通过对 Response 类 扩展 ,以下是对这两种方式的封装

其一:使用 ObjectMapper库 把JSON 转换成 Model

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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中,使用已经封装好的接口进行网络请求,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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: -- 网络
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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"]
  }
}

其二、实现协议 HandyJSON

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 进行网络请求的分析,接下来看一个示例如何使用,在MainClassViewModel 中我们使用 dataSource 保存了网络请求回来的数据,我们要在 ViewController里 用tableview 把这个数据展示出来,需要提前把数据源和TableView进行绑定,以下是示例代码:

?
1
2
3
4
5
6
7
8
9
//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

demo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://www.jianshu.com/p/d8cf13724fe7

延伸 · 阅读

精彩推荐
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22