RxSwift是在 Apple 推出 Swift 后, ReactiveX 推出 Reactive Extensions 系列一个实现库。下面介绍工作中使用RxSwift解决异步网络请求场景的实践。
img img业务场景为根据当前定位位置请求附近公交、地铁、水巴数据。根据右侧的筛选项筛选出不同的数据,进行请求。
创建数据事件源Observable
- 请求地铁网络数据
func searchSubwayData(_ location: CLLocationCoordinate2D, _ isUserLocation: Bool = false) -> Observable<Bool> {
return Observable<Bool>.create { [weak self] (observer) -> Disposable in
let send = SubwaySendModel()
send.latitude = location.latitude
send.longitude = location.longitude
send.range = 500
SubwayNetwork.This.doTask(SubwayNetwork.CMD_getByCoord, data: send, controller: nil, success: {[weak self] (response: SubwayResponseModel?) in
observer.onCompleted()
guard let resp = response else {return}
guard resp.line.count > 0 else {return}
if isUserLocation == true {
self?.subWayResponseModel = nil
self?.subWayResponseModel = response
}
guard resp.station.count > 0 else {return}
guard let stations: [SubwayStationModel] = (resp.station as NSArray).jsonArray() else {return}
for model in stations {
let annotation = RyHomeMAPointAnnotation(.subway)
annotation.title = model.name
annotation.coordinate = JZLocationConverter.wgs84(toGcj02: CLLocationCoordinate2D.init(latitude: CLLocationDegrees(model.latitude), longitude: CLLocationDegrees(model.longitude)))
let nearStationModel = RyHomeNearStationModel()
nearStationModel.name = model.name
nearStationModel.desc = model.lines
let nlocation = CLLocation.init(latitude: annotation.coordinate.latitude, longitude: annotation.coordinate.longitude)
nearStationModel.sid = "\(model.id)"
nearStationModel.mtype = .subway
if let userLocation = self?.mapView.userLocation.location {
nearStationModel.locationDistance = userLocation.distance(from: nlocation)
}
nearStationModel.location = nlocation
annotation.mStationModel = nearStationModel
self?.nearStationModelArr.append(nearStationModel)
self?.subwayAnnotations.append(annotation)
}
self?.mapView.addAnnotations(self?.subwayAnnotations)
}, error: { [weak self] (err, msg) in
self?.subWayResponseModel = nil
observer.onError(TestError.test)
}, com: nil, showWait: false)
return Disposables.create()
}
}
- 请求水巴网络数据
func searchBoatData(_ location: CLLocationCoordinate2D, _ isUserLocation: Bool = false) -> Observable<Bool> {
return Observable<Bool>.create { [weak self] (observer) -> Disposable in
let send = WaterBusSendModel()
send.latitude = location.latitude
send.longitude = location.longitude
send.range = 500
WaterBusNetWork.This.doArrayTask(WaterBusNetWork.CMD_getByCoord, data: send, controller: nil, success: { [weak self] (response: [ShuiBaStationModel]?) in
observer.onCompleted()
guard let stations = response else {return}
guard stations.count > 0 else {return}
if isUserLocation == true {
self?.shuibaResponseArr = nil
self?.shuibaResponseArr = stations
}
for model in stations {
let annotation = RyHomeMAPointAnnotation(.boat)
annotation.title = model.n
annotation.coordinate = JZLocationConverter.wgs84(toGcj02: CLLocationCoordinate2D.init(latitude: CLLocationDegrees(model.la), longitude: CLLocationDegrees(model.lo)))
let nearStationModel = RyHomeNearStationModel()
nearStationModel.name = model.n
nearStationModel.desc = "途径\(model.rcount ?? "0")条线路"
let nlocation = CLLocation.init(latitude: annotation.coordinate.latitude, longitude: annotation.coordinate.longitude)
nearStationModel.sid = model.i
nearStationModel.mtype = .boat
if let userLocation = self?.mapView.userLocation.location {
nearStationModel.locationDistance = userLocation.distance(from: nlocation)
}
nearStationModel.location = nlocation
annotation.mStationModel = nearStationModel
self?.nearStationModelArr.append(nearStationModel)
self?.boatAnnotations.append(annotation)
}
self?.mapView.addAnnotations(self?.boatAnnotations)
}, error: { [weak self] (_, _) in
self?.shuibaResponseArr = nil
observer.onError(TestError.test)
}, com: nil, showWait: false)
return Disposables.create()
}
}
- 请求公交站网络数据
func searchBusStationData(_ location: CLLocationCoordinate2D) -> Observable<Bool> {
return Observable<Bool>.create { [weak self] (observer) -> Disposable in
let send = SendGetFullStationByCoord()
send.latitude = location.latitude
send.longitude = location.longitude
send.range = 500
send.withLCheck = true
BusNetWork.This.doArrayTask(BusNetWork.CMD_getByCoord, data: send, controller: self, success: { (responseObj:[GetFullStationByCoord]?) in
observer.onCompleted()
guard let stations = responseObj else {return}
guard stations.count > 0 else {return}
for model in stations {
let annotation = RyHomeMAPointAnnotation(.busStation)
annotation.title = model.n
annotation.coordinate = JZLocationConverter.wgs84(toGcj02: CLLocationCoordinate2D.init(latitude: CLLocationDegrees(model.la), longitude: CLLocationDegrees(model.lo)))
let nearStationModel = RyHomeNearStationModel()
nearStationModel.name = model.n
nearStationModel.desc = "途径\(model.c)条线路"
let nlocation = CLLocation.init(latitude: annotation.coordinate.latitude, longitude: annotation.coordinate.longitude)
nearStationModel.sid = model.i
nearStationModel.mtype = .busStation
nearStationModel.linec = Int(model.c)
if let userLocation = self?.mapView.userLocation.location {
nearStationModel.locationDistance = userLocation.distance(from: nlocation)
}
nearStationModel.location = nlocation
annotation.mStationModel = nearStationModel
self?.nearStationModelArr.append(nearStationModel)
self?.busStationAnnotations.append(annotation)
}
self?.mapView.addAnnotations(self?.busStationAnnotations)
}, error: { (_, _) in
observer.onError(TestError.test)
}, com: nil, showWait: false)
return Disposables.create()
}
}
代码中Observable<Bool>.create { }
是创建一个被观察者,observer.onCompleted()
是网络数据请求回来,当前观察者发送完成信号,开始处理下一个事件,observer.onError(TestError.test)
是网络请求失败,发送失败信号,使整个事件序列重新开始请求。
Observable就是可被观察的,是事件源,可以被订阅,上面创建了三个Observable,下面我们可以通过concat,把创建的三个事件联合起来一起被订阅。
联合订阅事件源
let disposeBag = DisposeBag()
func getData(_ isUserLocation: Bool = false) {
ryHomeRightCategoryView.updateFilterIcon(filterType)
guard let location = movedLocationCoordinate else {return}
mapView.removeOverlays(mapView.overlays)
addOverlay(location)
mapView.removeAnnotations(subwayAnnotations)
mapView.removeAnnotations(boatAnnotations)
mapView.removeAnnotations(busStationAnnotations)
subwayAnnotations.removeAll()
boatAnnotations.removeAll()
busStationAnnotations.removeAll()
nearStationModelArr.removeAll()
let wgsLocation = JZLocationConverter.gcj02(toWgs84: location)
let symbol1 = searchSubwayData(wgsLocation)
let symbol2 = searchBoatData(wgsLocation)
let symbol3 = searchBusStationData(wgsLocation)
var symbols: Observable<Observable<Bool>>? = nil
if filterType == .subway {
symbols = Observable.of(symbol1)
}
else if filterType == .boat {
symbols = Observable.of(symbol2)
}
else if filterType == .bus {
symbols = Observable.of(symbol3)
}
else if filterType == .all {
symbols = Observable.of(symbol1, symbol2, symbol3)
}
symbols?.concat().retry(2).subscribe().addDisposableTo(disposeBag)
}
这个方法,通过concat把几个事件源联合起来进行订阅,就实现了多个网络的链式顺序请求。
- 创建了地铁、水巴、公交站台三个被观察者的对象,这样方便后面进行筛选数据。
let symbol1 = searchSubwayData(wgsLocation)
let symbol2 = searchBoatData(wgsLocation)
let symbol3 = searchBusStationData(wgsLocation)
- 创建事件源序列对象
var symbols: Observable<Observable<Bool>>? = nil
根据当前的筛选类型filterType
,给symbols
进行赋值
var symbols: Observable<Observable<Bool>>? = nil
if filterType == .subway {
symbols = Observable.of(symbol1)
}
else if filterType == .boat {
symbols = Observable.of(symbol2)
}
else if filterType == .bus {
symbols = Observable.of(symbol3)
}
else if filterType == .all {
symbols = Observable.of(symbol1, symbol2, symbol3)
}
- 联合订阅事件,把当前事件添加到释放池
disposeBag
,方便当前页面被释放后,被订阅的事件可以被释放。
symbols?.concat().retry(2).subscribe().addDisposableTo(disposeBag)
网友评论