RxSwift:防止多个网络请求
RxSwift: Prevent multiple network requests
我目前在使用 RxSwift Observables 时遇到执行多个网络请求的问题。我知道如果一个人创建了一个冷的可观察对象并且它有多个观察者,那么可观察对象将在每次订阅时执行它的块。
我试过创建一个共享订阅observable,执行一次网络请求,多个订阅者会收到结果通知。以下是我尝试过的。
事件顺序
- 使用 uibutton 的点击事件创建视图模型
- 在视图模型上创建 serviceStatus Observable 作为 public 属性。这个 Observable 是从 buttonTapped Observable 映射而来的。然后过滤掉 "Loading" 状态。 returned Observable 执行了一个 shareReplay(1) 到 return 共享订阅。
- 在视图模型上将 serviceExecuting Observable 创建为 public 属性。这个 observable 是从 serviceStatus Observable 映射而来的。如果状态为 "Loading"
,它将 return 为真
- 将 uilabel 绑定到 serviceStatus Observable
- 将 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
只创建一次,因此每次使用它的副作用都会共享,因为它是相同的实例。
我目前在使用 RxSwift Observables 时遇到执行多个网络请求的问题。我知道如果一个人创建了一个冷的可观察对象并且它有多个观察者,那么可观察对象将在每次订阅时执行它的块。
我试过创建一个共享订阅observable,执行一次网络请求,多个订阅者会收到结果通知。以下是我尝试过的。
事件顺序
- 使用 uibutton 的点击事件创建视图模型
- 在视图模型上创建 serviceStatus Observable 作为 public 属性。这个 Observable 是从 buttonTapped Observable 映射而来的。然后过滤掉 "Loading" 状态。 returned Observable 执行了一个 shareReplay(1) 到 return 共享订阅。
- 在视图模型上将 serviceExecuting Observable 创建为 public 属性。这个 observable 是从 serviceStatus Observable 映射而来的。如果状态为 "Loading" ,它将 return 为真
- 将 uilabel 绑定到 serviceStatus Observable
- 将 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
只创建一次,因此每次使用它的副作用都会共享,因为它是相同的实例。