Search code examples
iosobservablerx-swiftsubject-observerpublishsubject

RxSwift trigger observable execution


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?


Solution

  • 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.