Home Articles

RxSwift:防止多个网络请求

Asked
Viewed 1883 times
1

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

我已经尝试创建一个执行网络请求的共享订阅observable,并且会通知多个订阅者结果 . 以下是我的尝试 .

Sequence of events

  • 使用uibutton的tap事件创建视图模型

  • 在视图模型上创建serviceStatus Observable作为公共属性 . 此Observable从buttonTapped Observable映射 . 然后它过滤掉"Loading"状态 . 返回的Observable在其上执行了shareReplay(1)以返回共享订阅 .

  • 在视图模型上将serviceExecuting Observable创建为公共属性 . 此observable是从serviceStatus Observable映射的 . 如果状态为"Loading",它将返回true

  • 将uilabel绑定到serviceStatus Observable

  • 将活动指示符绑定到serviceExecuting Observable .

当点击按钮时,服务请求被执行三次,我希望它只执行一次 . 有什么突出的不正确吗?

Code

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)
}

EDIT:

基于下面的对话,以下是我正在寻找的......

我需要对从getServiceStatusObservable()方法返回的Observable应用share()函数,而不是从createServiceStatusObservable()方法返回的Observable . 有多个观察者被添加到这个观察者以检查当前状态 . 这意味着执行网络请求的可观察对象被执行了N次(N是观察者的数量) . 现在每次点击按钮,网络请求都会执行一次,这就是我需要的 .

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

1 Answer

  • 4

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

Related