欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

浅谈RxSwift 网络请求

程序员文章站 2023-12-10 16:16:40
一、说明 入坑rxswift 有段时间了,之前在项目中只是小范围的使用rxswift,为了更好的使用响应式编程,决定在项目中更广范围的使用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 协议就好,用一个例子来看下怎么使用:

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

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中,使用已经封装好的接口进行网络请求,代码如下:

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

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

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进行绑定,以下是示例代码:

 //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

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