RxSwift是在 Apple 推出 Swift 后冒滩, ReactiveX 推出 Reactive Extensions 系列一個(gè)實(shí)現(xiàn)庫竹揍。下面介紹工作中使用RxSwift解決異步網(wǎng)絡(luò)請(qǐng)求場景的實(shí)踐。
業(yè)務(wù)場景為根據(jù)當(dāng)前定位位置請(qǐng)求附近公交官撼、地鐵、水巴數(shù)據(jù)。根據(jù)右側(cè)的篩選項(xiàng)篩選出不同的數(shù)據(jù)褪贵,進(jìn)行請(qǐng)求。
創(chuàng)建數(shù)據(jù)事件源Observable
- 請(qǐng)求地鐵網(wǎng)絡(luò)數(shù)據(jù)
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()
}
}
- 請(qǐng)求水巴網(wǎng)絡(luò)數(shù)據(jù)
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()
}
}
- 請(qǐng)求公交站網(wǎng)絡(luò)數(shù)據(jù)
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 { }
是創(chuàng)建一個(gè)被觀察者抗俄,observer.onCompleted()
是網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求回來脆丁,當(dāng)前觀察者發(fā)送完成信號(hào),開始處理下一個(gè)事件动雹,observer.onError(TestError.test)
是網(wǎng)絡(luò)請(qǐng)求失敗槽卫,發(fā)送失敗信號(hào),使整個(gè)事件序列重新開始請(qǐng)求胰蝠。
Observable就是可被觀察的晒夹,是事件源,可以被訂閱姊氓,上面創(chuàng)建了三個(gè)Observable丐怯,下面我們可以通過concat,把創(chuàng)建的三個(gè)事件聯(lián)合起來一起被訂閱翔横。
聯(lián)合訂閱事件源
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)
}
這個(gè)方法读跷,通過concat把幾個(gè)事件源聯(lián)合起來進(jìn)行訂閱,就實(shí)現(xiàn)了多個(gè)網(wǎng)絡(luò)的鏈?zhǔn)巾樞蛘?qǐng)求禾唁。
- 創(chuàng)建了地鐵效览、水巴、公交站臺(tái)三個(gè)被觀察者的對(duì)象荡短,這樣方便后面進(jìn)行篩選數(shù)據(jù)丐枉。
let symbol1 = searchSubwayData(wgsLocation)
let symbol2 = searchBoatData(wgsLocation)
let symbol3 = searchBusStationData(wgsLocation)
- 創(chuàng)建事件源序列對(duì)象
var symbols: Observable<Observable<Bool>>? = nil
根據(jù)當(dāng)前的篩選類型filterType
,給symbols
進(jìn)行賦值
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)
}
- 聯(lián)合訂閱事件掘托,把當(dāng)前事件添加到釋放池
disposeBag
瘦锹,方便當(dāng)前頁面被釋放后,被訂閱的事件可以被釋放。
symbols?.concat().retry(2).subscribe().addDisposableTo(disposeBag)