YichenBman
YichenBman

Reputation: 5651

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?

Upvotes: 2

Views: 2253

Answers (2)

Iman Rosstin
Iman Rosstin

Reputation: 2345

Probably using a flatMapLatest is a designated solution to this problem.However, I would like to propose another solution :

Simply re-initialize your BehaviorRelay again in your subscribe part of your code, and filter empty ones, Like this :

  addresses.asObservable().filter({$0.count >0}).subscribe(onNext: { [unowned self] (value) in
    self.fetchAllAnnotationsAndAddToMap()
    self.addresses = BehaviorRelay<[Address]>(value: [])
}).disposed(by: disposebag)

Upvotes: 1

Daniel T.
Daniel T.

Reputation: 33967

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)

Upvotes: 2

Related Questions