我目前在使用 RxSwift Observables 时遇到执行多个网络请求的问题。我知道如果一个人创建了一个冷的可观察对象并且它有多个观察者,那么可观察对象将在每次订阅时执行它的 block 。
我尝试创建一个执行一次网络请求的共享订阅可观察对象,多个订阅者将收到结果通知。以下是我尝试过的。
事件的顺序
- 使用 uibutton 的点击事件创建 View 模型
- 创建 serviceStatus Observable 作为 View 模型的公共(public)属性。这个 Observable 是从 buttonTapped Observable 映射而来的。然后它会过滤掉“正在加载”状态。返回的 Observable 在其上执行了 shareReplay(1) 以返回共享订阅。
- 创建 serviceExecuting Observable 作为 View 模型的公共(public)属性。这个 observable 是从 serviceStatus Observable 映射而来的。如果状态为“正在加载”,它将返回 true
- 将 uilabel 绑定(bind)到 serviceStatus Observable
- 将事件指示器绑定(bind)到 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。有多个观察者被添加到这个可观察对象中以检查当前状态。这意味着执行网络请求的可观察对象被执行了 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
只创建一次,因此它的副作用将在每次使用时共享,因为它是同一个实例。
关于ios - Rx swift : Prevent multiple network requests,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41681198/