1

I have a Subject observable representing the result of the network request that needs to be delivered to multiple subscribers.

I can use ReplaySubject of buffer 1 and publish() method. However, the network request gets executed only once.

I'd like to trigger the fetch event at any give point in the future. How can I trigger a new requst?

Currently, I have a Service object that holds the ReplaySubject and has a method reload() which triggers the network request and publishes the result to the aReplaySubject.

Is there any method on Observable that can "refresh" it and deliver a new value to all the current subscribers?

Richard Topchii
  • 7,075
  • 8
  • 48
  • 115

1 Answers1

3

If I'm interpreting this question correctly, this is a fairly common problem in RxSwift. You need to be able to recreate your network request Observable each time your fetch is "triggered," but you need these results delivered on a single Observable that only gets created once, and has multiple subscribers. This is done with a flatMap:

struct Service {
    var resultsObservable: Observable<Results> {
        return resultsSubject.asObservable()
    }

    private let resultsSubject: ReplaySubject<Results> = .create(bufferSize: 1)
    private let reloadSubject = PublishSubject<Void>()
    private let disposeBag = DisposeBag()

    init() {
        bindFetch()
    }

    func reload() {
        reloadSubject.onNext(())
    }

    private func bindFetch() {
        reloadSubject
            .asObservable()
            .flatMap(fetch)
            .bind(to: resultsSubject)
            .disposed(by: disposeBag)
    }

    private func fetch() -> Observable<Results> {
        // URLSession just one example
        let urlRequest = URLRequest(url: URL(string: "https://apple.com")!)
        return URLSession
            .shared
            .rx
            .data(request: urlRequest)
            .map(Results.init)
            .catchErrorJustReturn(Results.empty())
    }
}

In this example, you can subscribe to resultsObservable multiple times, and each should be updated after a new reload() occurs.

dalton_c
  • 6,876
  • 1
  • 33
  • 42
  • Thanks for your response. I've implemented the desired functionality the way you've described in your answer. However, the question is whether it is possible to refresh `resultsObservable` by invoking some method call on the observable itself, not the `reload()` method on the service. – Richard Topchii May 02 '18 at 07:29
  • In this example, rather than calling `reload()`, you can bind an `Observable` to the `reloadSubject`, for example, `UIButton.rx.tap` – dalton_c May 03 '18 at 01:47