Search code examples
swiftreactive-programmingrx-swift

RxSwift BehaviorRelay cancel previous calls, only use the most recent


I have a BehaviorRelay setup to store an array of addresses, and then I observe that BehaviorRelay so that I can create an MKAnnotation array and then display that on the map.

let addresses = BehaviorRelay<[Address]>(value: [])

I make network requests when the user moves the map to a new area. If the user moves the map very quickly, I can end up with several network requests

I only want the latest response.

This is where my problem begins.

    addresses.asObservable().subscribe(onNext: { [unowned self] (value) in
        self.fetchAllAnnotationsAndAddToMap()
    }).disposed(by: disposebag)

fetchAllAnnotationsAndAddToMapgets called every time addresses is set.

fetchAllAnnotationsAndAddToMap can take a long time to complete. Requests to run fetchAllAnnotationsAndAddToMapget stacked up and all of them run to completion.

What I want to happen is once addresses is set again, I want for all former calls to be discarded and only use the latest.

I've heard this is what flatMapLatest is for.

However, flatMapLatest requires I return an observable and I'm confused by that.

How do I cancel the methods called after the BehaviorRelay is updated and only use the most recent?


Solution

  • First you need to break up your fetchAllAnnotationsAndAddToMap() function into two functions. Then you can:

    addresses.asObservable()
        // you might want to put a `debounce` call in here.
        .flatMapLatest { addresses in 
            return fetchAllAnnotations(from: addresses)
        }
        .subscribe(onNext: { [weak self] annotations in 
            self?.addToMap(annotations)
        }
        .disposed(by: disposeBag)