浅谈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协议就好,用一个例子来看下怎么使用:
importFoundation
importMoya
enumAPIService{
casemainClassList
}
extensionAPIService:TargetType{
varbaseURL:URL{
returnURL(string:"http://cmsadmin.fotoable.net")!
}
varpath:String{
switchself{
case.mainClassList:
return"/sandboxColor/category"
}
}
varmethod:Moya.Method{
switchself{
case.mainClassList:
return.get
}
}
varparameters:[String:Any]?{
switchself{
case.mainClassList:
returnnil
}
}
varparameterEncoding:ParameterEncoding{
returnURLEncoding.default
}
varsampleData:Data{
return"{}".data(using:String.Encoding.utf8)!
}
vartask:Task{
return.requestPlain
}
varheaders:[String:String]?{
returnnil
}
}
首先,我们定义了一个枚举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
importFoundation
importRxSwift
importMoya
importObjectMapper
//MARK:-Json->Model
extensionResponse{
funcmapObjectModel(_type:T.Type,context:MapContext?=nil)throws->T{
guardletobject=Mapper(context:context).map(JSONObject:trymapJSON())else{
throwMoyaError.jsonMapping(self)
}
returnobject
}
funcmapObjectArray(_type:T.Type,context:MapContext?=nil)throws->[T]{
guardletarray=trymapJSON()as?[[String:Any]]else{
throwMoyaError.jsonMapping(self)
}
returnMapper(context:context).mapArray(JSONArray:array)
}
}
//MARK:-Json->Observable
extensionObservableTypewhereE==Response{
//将Json解析为Observable
publicfuncmapObjectModel(_type:T.Type)->Observable{
returnflatMap{response->Observablein
returnObservable.just(tryresponse.mapObjectModel(T.self))
}
}
//将Json解析为Observable<[Model]>
publicfuncmapObjectArray(_type:T.Type)->Observable<[T]>{
returnflatMap{response->Observable<[T]>in
returnObservable.just(tryresponse.mapObjectArray(T.self))
}
}
}
其二:使用HandyJSON库把JSON转化成Model
importFoundation
importRxSwift
importMoya
importHandyJSON
extensionObservableTypewhereE==Response{
publicfuncmapHandyJsonModel(_type:T.Type)->Observable{
returnflatMap{response->Observablein
returnObservable.just(response.mapHandyJsonModel(T.self))
}
}
}
extensionResponse{
funcmapHandyJsonModel(_type:T.Type)->T{
letjsonString=String.init(data:data,encoding:.utf8)
ifletmodelT=JSONDeserializer.deserializeFrom(json:jsonString){
returnmodelT
}
returnJSONDeserializer.deserializeFrom(json:"{\"msg\":\"请求有误\"}")!
}
}
4.在MainClassViewModel中,使用已经封装好的接口进行网络请求,代码如下:
importRxSwift
importMoya
importObjectMapper
importHandyJSON
importRxCocoa
classMainClassViewModel{
privateletprovider=MoyaProvider()
letdisposeBag=DisposeBag()
vardataSource=BehaviorRelay<[MainClassModelMapObject_sub]>(value:[])
varnetworkError=BehaviorRelay(value:Error.self)
}
//MARK:--网络
extensionMainClassViewModel{
//网络请求--ObjectMapper
funcgetClassListWithMapObject(){
provider.rx.request(.mainClassList).asObservable().mapObjectModel(MainClassModelMapObject.self).subscribe({[unownedself](event)in
switchevent{
caselet.next(classModel):
print("ObjectMapper--加载网络成功")
self.dataSource.accept(classModel.data)
caselet.error(error):
print("error:",error)
self.networkError.accept(erroras!Error.Protocol)
case.completed:break
}
}).disposed(by:self.disposeBag)
}
//网络请求--HandyJSON
funcgetClassListWithMapHandyJson(){
provider.rx.request(.mainClassList).asObservable().mapHandyJsonModel(MainClassModel.self).subscribe({[unownedself](event)in
switchevent{
caselet.next(classModel):
print("HandyJSON--加载网络成功")
caselet.error(error):
print("error:",error)
self.networkError.accept(erroras!Error.Protocol)
case.completed:break
}
}).disposed(by:self.disposeBag)
}
}
这里用了两种方式,分别对mainClassListAPI接口进行了网络请求,唯一不同的是,在得到到网络请求回来数据的时候,一个是使用mapObjectModel把JSON转化成Model,一个是使用mapHandyJsonModel把JSON转化成Model,由于我们使用的是不同的库,把JSON转化成Model,这两种实现的方式还是有一些差别,下面是这两种Model的具体实现方式:
其一、实现协议Mappable
importUIKit
importObjectMapper
classMainClassModelMapObject:Mappable{
varcode:NSInteger?
vardata:[MainClassModelMapObject_sub]!
requiredinit?(map:Map){}
funcmapping(map:Map){
code<-map["code"]
data<-map["data"]
}
}
classMainClassModelMapObject_sub:Mappable{
varID:String?
varname:String?
vardesc:String?
varimgUrl:String?
vargifUrl:String?
varisUpdate:Bool?
varbackgroundGroup:NSInteger?
requiredinit?(map:Map){}
funcmapping(map:Map){
ID<-map["ID"]
name<-map["name"]
desc<-map["desc"]
imgUrl<-map["imgUrl"]
gifUrl<-map["gifUrl"]
isUpdate<-map["isUpdate"]
backgroundGroup<-map["backgroundGroup"]
}
}
其二、实现协议HandyJSON
importUIKit
importHandyJSON
structMainClassModel:HandyJSON{
varcode:NSInteger?
vardata:[MainClassModel_sub]!
}
structMainClassModel_sub:HandyJSON{
varID:String?
varname:String?
vardesc:String?
varimgUrl:String?
vargifUrl:String?
varisUpdate:Bool?
varbackgroundGroup:NSInteger?
}
5、以上是使用RxSwift进行网络请求的分析,接下来看一个示例如何使用,在MainClassViewModel中我们使用dataSource保存了网络请求回来的数据,我们要在ViewController里用tableview把这个数据展示出来,需要提前把数据源和TableView进行绑定,以下是示例代码:
//cell
viewModel.dataSource.bind(to:tableView.rx.items){(tableView,row,element)in
letcell=tableView.dequeueReusableCell(withIdentifier:"MainClassTableViewCell",for:IndexPath(row:row,section:0))as!MainClassTableViewCell
cell.setModel(model:element)
//configurecell
returncell
}
.disposed(by:disposeBag)
在需要使用的地方,调用方法getClassListWithMapObject()或者getClassListWithMapHandyJson()
三、总结
这部分的内容,适合对RxSwift有一定了解的小伙伴学习,文章重点是帮助大家学习和了解RxSwift网络请求的相关知识,下面是一个写好的demo
demo
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。