RxSwift:防止多个网络请求
问题描述:
我目前在使用RxSwift Observables时执行多个网络请求时会出现问题。我明白,如果一个人创建了一个冷观察者,并且它有多个观察者,那么观察者将在每次订阅时执行它的块。RxSwift:防止多个网络请求
我试图创建一次执行网络请求的共享订阅observable,并将多个订户通知结果。以下是我所尝试的。事件
- 的
序列与一个UIButton
- 的点击事件创建视图模型创建serviceStatus观察为上视图模型公共财产。这个Observable从buttonTapped Observable映射而来。然后过滤掉“加载”状态。返回的Observable在其上执行shareReplay(1)以返回共享订阅。
- 在视图模型上创建serviceExecuting Observable作为公共属性。这个可观察值是从serviceStatus Observable映射而来的。如果状态是“加载”
- 绑定的UILabel到serviceStatus可观察
- 绑定活动的指标为serviceExecuting可观察到它会返回true。
当按钮被点击时,服务请求被执行三次,我期待它只被执行一次。有什么事情脱颖而出吗?
代码
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,而不是从createServiceStatusObservable()方法返回的Observable。有多名观察员被添加到这个观察者来检查当前状态。这意味着执行网络请求的observable被执行了N次(N是观察者的数量)。现在每次点击按钮时,网络请求都会执行一次,这正是我所需要的。
private func getServiceStatusObservable() -> Observable<String> {
return self.buttonTapped.flatMap { _ -> Observable<String> in
return self.createServiceStatusObservable()
}.share()
}
答
.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()to share(),因为我不希望缓存结果,因为用户可以多次点击该按钮来执行新的服务请求。这是否意味着我应该对所有其他可观察的事件做同样的事情,因为按钮的后续点击会导致对该服务的多个请求。 –
只要在第一次订阅取消订阅之前完成对其他观察对象的订阅,就可以仅在网络请求上保留“共享”。 (在这种情况下,将执行新的请求)。 'share()'记录在[这里](https://github.com/ReactiveX/RxSwift/blob/3c55a309a24fbe3dbc480431798eec072b633b85/RxSwift/Observables/Observable%2BBinding.swift#L136)。 – tomahh
哎呀。我猜想我在这里对getServiceStatusObservable()方法感到困惑。点击按钮时,已注册的块被调用三次。 {[weak self] _ - > Observable in return self.serviceStatusObservable } –