mike
mike

Reputation: 2193

switchToLatest in Combine doesn't behave as expected

I've been trying to replicate flatMapLatest from RxSwift in Combine, I've read in a few places that the solution is to use .map(...).switchToLatest

I'm finding some differences between the two, and I'm not sure if it's my implementation/understanding which is the problem.

In RxSwift if the upstream observable emits a stop event (completed or error) then the downstream observables created in the flatMapLatest closure will continue to emit events until they themselves emit a stop event:

let disposeBag = DisposeBag()

func flatMapLatestDemo() {
    let mockTrigger = PublishSubject<Void>()
    let mockDataTask = PublishSubject<Void>()

    mockTrigger
        .flatMapLatest { mockDataTask }
        .subscribe(onNext: { print("RECEIVED VALUE") })
        .disposed(by: disposeBag)

    mockTrigger.onNext(())
    mockTrigger.onCompleted()

    mockDataTask.onNext(()) // -> "RECEIVED VALUE" is printed
}

This same setup in Combine doesn't behave the same way:

var cancellables = Set<AnyCancellable>()

func switchToLatestDemo() {
    let mockTrigger = PassthroughSubject<Void, Never>()
    let mockDataTask = PassthroughSubject<Void, Never>()

    mockTrigger
        .map { mockDataTask }
        .switchToLatest()
        .sink { print("RECEIVED VALUE") }
        .store(in: &cancellables)

    mockTrigger.send(())
    mockTrigger.send(completion: .finished)

    mockDataTask.send(()) // -> Nothing is printed, if I uncomment the finished event above then "RECEIVED VALUE" is printed
}

Is this intentional? If so, how do we replicate the behaviour of flatMapLatest in Combine?

If it's not intentional, file a radar I guess?

Upvotes: 1

Views: 1332

Answers (1)

LuLuGaGa
LuLuGaGa

Reputation: 14388

I've using this Swift implementation by sergdort:

func flatMapLatest<T: Publisher>(_ transform: @escaping (Self.Output) -> T) -> Publishers.SwitchToLatest<T, Publishers.Map<Self, T>> where T.Failure == Self.Failure {
    map(transform).switchToLatest()
}

Upvotes: 4

Related Questions