RxSwift:防止多个网络请求

RxSwift: Prevent multiple network requests

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

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

事件顺序

  1. 使用 uibutton 的点击事件创建视图模型
  2. 在视图模型上创建 serviceStatus Observable 作为 public 属性。这个 Observable 是从 buttonTapped Observable 映射而来的。然后过滤掉 "Loading" 状态。 returned Observable 执行了一个 shareReplay(1) 到 return 共享订阅。
  3. 在视图模型上将 serviceExecuting Observable 创建为 public 属性。这个 observable 是从 serviceStatus Observable 映射而来的。如果状态为 "Loading"
  4. ,它将 return 为真
  5. 将 uilabel 绑定到 serviceStatus Observable
  6. 将 activity 指标绑定到 serviceExecuting Observable。

当点击按钮时,服务请求执行了三次,而我希望它只执行一次。有什么明显不正确的地方吗?

代码

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() 方法 returned 的 Observable 上应用一个 share() 函数,而不是从 createServiceStatusObservable() 方法 returned 的 Observable。有多个观察者被添加到这个可观察对象中以检查当前状态。这意味着执行网络请求的可观察对象被执行了 N 次(N 是观察者的数量)。现在每次点击按钮时,网络请求都会执行一次,这正是我所需要的。

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

.shareReplay(1) 将仅应用于可观察对象的一个​​实例。在 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只创建一次,因此每次使用它的副作用都会共享,因为它是相同的实例