RxSwift:防止多个网络请求

时间:2017-01-16 16:49:30

标签: ios rx-swift reactivex

我目前在使用RxSwift Observable时执行多个网络请求时遇到问题。我知道如果一个人创建了一个冷可观察对象并且它有多个观察者,那么observable将在每次订阅时执行它的块。

我尝试创建一次执行网络请求的共享订阅observable,并会通知多个订阅者结果。以下是我的尝试。

活动顺序

  1. 使用uibutton的点击事件
  2. 创建视图模型
  3. 在视图模型上将serviceStatus Observable创建为公共属性。此Observable从buttonTapped Observable映射。然后它过滤掉“正在加载”状态。返回的Observable在其上执行了shareReplay(1)以返回共享订阅。
  4. 在视图模型上将serviceExecuting Observable创建为公共属性。此observable是从serviceStatus Observable映射的。如果状态为“正在加载”
  5. ,它将返回true
  6. 将uilabel绑定到serviceStatus Observable
  7. 将活动指示器绑定到serviceExecuting Observable。
  8. 当点击按钮时,服务请求执行三次,我希望它只执行一次。有什么突出的不正确吗?

    代码

    class ViewController {
    
        let disposeBag = DisposeBag()
        var button: UIButton!
        var resultLabel: UILabel!
        var activityIndicator: UIActivityIndicator!
    
        lazy var viewModel = { // 1
            return ViewModel(buttonTapped: self.button.rx.tap.asObservable())
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.viewModel.serviceStatus.bindTo(self.resultLabel.rx_text).addDispsoableTo(disposeBag) // 4
            self.viewModel.serviceExecuting.bindTo(self.activityIndicator.rx_animating).addDispsoableTo(disposeBag) // 5
        }
    }
    
    class ViewModel {
    
        public var serviceStatus: Observable<String> { // 2
            let serviceStatusObseravble = self.getServiceStatusObservable()
            let filtered = serviceStatusObseravble.filter { status in
                return status != "Loading"
            }
            return filtered
        }
    
        public var serviceExecuting: Observable<Bool> { // 3
            return self.serviceStatus.map { status in
                return status == "Loading"
            }
            .startWith(false)
        }
    
        private let buttonTapped: Observable<Void>
    
        init(buttonTapped: Observable<Void>) {
            self.buttonTapped = buttonTapped
        }
    
        private func getServiceStatusObservable() -> Observable<String> {
            return self.buttonTapped.flatMap { _ -> Observable<String> in
                return self.createServiceStatusObservable()
            }
        }
    
        private func createServiceStatusObservable() -> Observable<String> {
            return Observable.create({ (observer) -> Disposable in
    
            someAsyncServiceRequest() { result }
                observer.onNext(result)
            })
    
            return NopDisposable.instance
        })
        .startWith("Loading")
        .shareReplay(1)
    }
    

    修改

    根据下面的对话,我正在寻找以下内容......

    我需要对从getServiceStatusObservable()方法返回的Observable应用share()函数,而不是从createServiceStatusObservable()方法返回的Observable。有多个观察者被添加到这个观察者以检查当前状态。这意味着执行网络请求的可观察对象被执行了N次(N是观察者的数量)。现在每次点击按钮,网络请求都会执行一次,这就是我需要的。

    private func getServiceStatusObservable() -> Observable<String> {
        return self.buttonTapped.flatMap { _ -> Observable<String> in
            return self.createServiceStatusObservable()
        }.share()
    }
    

1 个答案:

答案 0 :(得分:5)

.shareReplay(1)仅适用于observable的一个实例。在createServiceStatusObservable()中创建时,共享行为只会影响此函数返回的一个值。

class ViewModel {
  let serviceStatusObservable: Observable<String>

  init(buttonTapped: Observable<Void>) {
    self.buttonTapped = buttonTapped
    self.serviceStatusObservable = Observable.create({ (observer) -> Disposable in
        someAsyncServiceRequest() { result in
            observer.onNext(result)
        }

        return NopDisposable.instance
    })
    .startWith("Loading")
    .shareReplay(1)
  }

  private func getServiceStatusObservable() -> Observable<String> {
    return self.buttonTapped.flatMap { [weak self] _ -> Observable<String> in
      return self.serviceStatusObservable
    }
  }
}

使用此版本时,serviceStatusObservable只会创建一次,因此每次使用时都会分享副作用,因为它是相同的实例