Swift Combine: switchToLatest()

KD Knowledge Diet
2 min readJan 19, 2023

Let’s talk about a little bit of a more complicated combination operator, switchToLatest(). As the name suggests, switchToLatest() operator allows you to actually switch to a different publisher on the fly.

switchToLastest()

let publisher1 = PassthroughSubject<String, Never>()
let publisher2 = PassthroughSubject<String, Never>()
// Parent Publisher
let publishers = PassthroughSubject<PassthroughSubject<String, Never>, Never>
publishers
.switchToLastest()
.sink { value in // String
print(value)
}
// parent publisher temporarily subscribes to publisher1
publishers.send(publisher1)
// child publisher2
publisher1.send("Publisher 1 - Value 2") // Publisher 1 - Value 1
publisher1.send("Publisher 1 - Value 2") // Publisher 1 - Value 2
// switchToLatest()
publishers.send(publisher2) // switching to publisher2
// child publisher2
publisher2.send("Publisher 2 - Value 1") // Publisher 2 - Value 1
// child publisher1
publisher1.send("Publisher 1 - Value 3") // Not captured..

I created two PassthroughSubject. They take in String. And another third publisher which takes in PassthroughSubject<String, Never>. You can think of it as a parent publisher.

One of the things that you have to keep in mind is that publishers , the parent publisher, when it sinks, it gives you String not PassthroughSubject<String, Never>.

When the parent publisher sends an event, you can think of it as parent publisher subscribing to a child publisher. So whenever an event is generated from a child publisher, it will be captured by the parent publisher.

But what happens if your parent publisher subscribes to second child publisher with publishers.send(publisher2)? In this case, because you are using switchToLatest() operator, you will receive the event from the publisher2.

You must keep in mind, after your parent publisher subscribes to the second child publisher, publisher1’s event is ignored. Or you can simply call publishers.send(publisher1) to receive events from publisher1.

Practical Example

let images = ["cat", "dog", "tiger"]
let index = 0
func getImage() -> AnyPublisher<UIImage?, Never> {
return Future<UIImage?, Never> { promise in
promise(.success(UIImage(named: images[index])))
}
.map { $0 }
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}
// tap a button
let taps = PassthroughSubject<Void, Never>()
// Mapping Tap Publisher with AnyPublisher<UIImage?, Never>
let subscriptions = taps.map { _ in getImage() }
.switchToLastest()
.sink {
print($0) // image
}
taps.send() // image1 with publisher DispatchQueue.main.asyncAfter(deadline: .now() + 6.0) {
index += 1
taps.send() // image2 with publisher
}
DispatchQueue.main.asyncAfter(deadline: .now() + 6.5) {
index += 2
taps.send() // image 3 with publisher
}

I prepared cat, dog, tiger images locally. getImage() method returns publisher asynchronously with image.

Imagine taps.send() is actually a tap event from a user. Whenever users tap on something with taps.send(), it switches image. Using switchToLatest() operator, you can finally get the image from .sink() method.

Conclusion

  • switchToLatest() takes publishers.
  • Whenever send() occurs, it switches to the latest publisher and receives values from the latest publisher.

--

--

KD Knowledge Diet

Software Engineer, Mobile Developer living in Seoul. I hate people using difficult words. Why not using simple words? Keep It Simple Stupid!