当前位置: 移动技术网 > IT编程>移动开发>IOS > 浅谈RxSwift 网络请求

浅谈RxSwift 网络请求

2019年07月24日  | 移动技术网IT编程  | 我要评论

副区长获刑17年,平淡日子里的刺 歌词,晋嫣吧

一、说明

入坑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

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网