【问题标题】:RxSwift: Prevent multiple network requestsRxSwift:防止多个网络请求
【发布时间】:2017-01-16 16:49:30
【问题描述】:

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

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

事件顺序

  1. 使用 uibutton 的点击事件创建视图模型
  2. 将 serviceStatus Observable 创建为视图模型上的公共属性。这个 Observable 是从 buttonTapped Observable 映射而来的。然后它会过滤掉“正在加载”状态。返回的 Observable 执行了 shareReplay(1) 以返回共享订阅。
  3. 创建 serviceExecuting Observable 作为视图模型上的公共属性。这个 observable 映射自 serviceStatus Observable。如果状态为“正在加载”,它将返回 true
  4. 将 uilabel 绑定到 serviceStatus Observable
  5. 将活动指示器绑定到 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() 方法返回的 Observable 应用 share() 函数,而不是 createServiceStatusObservable() 方法返回的 Observable。有多个观察者被添加到这个 observable 来检查当前状态。这意味着执行网络请求的 observable 被执行了 N 次(N 是观察者的数量)。现在每次点击按钮时,网络请求都会执行一次,这正是我所需要的。

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

【问题讨论】:

    标签: ios rx-swift reactivex


    【解决方案1】:

    .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 仅创建一次,因此每次使用时都会共享其副作用,因为它是相同的实例

    【讨论】:

    • 那是个好地方,看起来在第一次点击按钮时解决了问题。我将 shareReplay() 更新为 share() 因为我不希望缓存结果,因为用户可以多次点击该按钮来执行新的服务请求。这是否意味着我应该对所有其他 observables 做同样的事情,因为随后点击按钮会导致对服务的多个请求。
    • 你可以只在网络请求上保留share,只要在第一个订阅被取消订阅之前完成了对其他可观察对象的订阅。 (在这种情况下,将执行一个新请求)。 share() 记录在案 here
    • 明白了。我猜我在这里对 getServiceStatusObservable() 方法感到困惑。当点击按钮时,注册的块被调用 3 次。 { [weak self] _ -> Observable 作为回报 self.serviceStatusObservable }
    • 看起来好像任何时候你给serviceStatus添加一个观察者,getServiceStatusObservable()方法中注册的block被调用的次数等于观察者的数量?
    • 是的。 share() 仅适用于 .share() 调用之上的内容。所以在getServiceStatusObservable() 中,调用flatMap 产生的observable 将不会被共享。但是serviceStatusObservable,会从flatMap返回。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-03
    • 1970-01-01
    相关资源
    最近更新 更多