RxSwift网络琏式请求总结

img

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)

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 发现 关注 消息 RxSwift入坑解读-你所需要知道的各种概念 沸沸腾关注 2016.11.27 19:11*字...
    枫叶1234阅读 2,869评论 0 2
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,246评论 19 139
  • 本篇文章介主要绍RxJava中操作符是以函数作为基本单位,与响应式编程作为结合使用的,对什么是操作、操作符都有哪些...
    嘎啦果安卓兽阅读 2,922评论 0 10
  • 亲爱的朋友, 祝好!现在窗外下着暴雨,电闪雷鸣,我躲在空调房里,给你写信。这场雨已经下了好几天了,不知为何,从昨...
    居无所处阅读 155评论 0 1
  • 死亡是一只静立的玻璃杯, 鲜血使它思想充盈, 注一剂冰冷,真理便在其中诞生。 一种欲望, 使它血脉狂贲,碎屑乘机浮...
    司贤阅读 395评论 0 1