ios - Rx swift : Prevent multiple network requests

标签 ios rx-swift reactivex

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

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

事件的顺序

  1. 使用 uibutton 的点击事件创建 View 模型
  2. 创建 serviceStatus Observable 作为 View 模型的公共(public)属性。这个 Observable 是从 buttonTapped Observable 映射而来的。然后它会过滤掉“正在加载”状态。返回的 Observable 在其上执行了 shareReplay(1) 以返回共享订阅。
  3. 创建 serviceExecuting Observable 作为 View 模型的公共(public)属性。这个 observable 是从 serviceStatus Observable 映射而来的。如果状态为“正在加载”,它将返回 true
  4. 将 uilabel 绑定(bind)到 serviceStatus Observable
  5. 将事件指示器绑定(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/

相关文章:

ios - 应用程序启动时在谷歌地图标记上打开信息窗口

swift - 无法在 RxSwift 中使用通用结果枚举出错

javascript - ReactiveX 对 observable 进行多次过滤并合并

rx-java - 防止多次 api 调用

swift - 带有 Moya 请求的 RxSwift 顺序平面图

ios - 如何创建一个自动上传iOS图片的应用程序?

ios - 从 NSString 对象返回的浮点值不是我所期望的,我该如何更正从 NSString 中提取 float ?

ios - 如何检查 Swift 3 中的当前线程?

swift - RXSwift 简单的异步示例?

rx-swift - 在 RxSwift 4.0.0 中正确使用 retryWhen 运算符