Use the flatMap
operator in Combine to transform elements from a publisher to another publisher.
import Combine
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let idPublisher = (1...5).publisher
var cancellables = Set<AnyCancellable>()
func fetchUserDetails(userId: Int) -> AnyPublisher<String, Never> {
let detail = "User details for \(userId)"
return Just(detail)
.delay(for: .milliseconds(userId * 1000), scheduler: RunLoop.main)
.eraseToAnyPublisher()
}
print("\(Date()) : Starting")
idPublisher
.flatMap(maxPublishers: .max(1)) { fetchUserDetails(userId: $0) }
.sink { print("\(Date()) : \($0)") }
.store(in: &cancellables)
In the above code:
- The
idPublisher
emits three elements: 1, 2, and 3. - The
fetchUserDetails
function takes anInt
as input and returns a publisher that emits a string. - The
flatMap
operator transforms the elements from theidPublisher
to another publisher using thefetchUserDetails
function. - Them
maxPublishers
parameter is used to specify the maximum number of publishers that can be active at a time. In this case, it is set to.max(1)
, which means only one publisher can be active at a time. - The
sink
operator subscribes to the publisher and prints the emitted values. - The
delay
operator is used to simulate a network request with a delay based on the user id.
When you run the code, you will see the following output:
2024-12-18 06:56:20 +0000 : Starting
2024-12-18 06:56:21 +0000 : User details for 1
2024-12-18 06:56:23 +0000 : User details for 2
2024-12-18 06:56:26 +0000 : User details for 3
2024-12-18 06:56:30 +0000 : User details for 4
2024-12-18 06:56:35 +0000 : User details for 5
In the above example, the maxPublishers
parameter is set to .max(1)
, which means only one publisher can be active at a time. This ensures that the fetchUserDetails
function is called sequentially for each element emitted by the idPublisher
.
If the maxPublishers
parameter is set to .max(2)
, two publishers can be active at a time, and the fetchUserDetails
function will be called concurrently for two elements emitted by the idPublisher
. Once one of the publishers completes, the next publisher will be activated.
In this example since we are using a delay to simulate a network request, the timing of printed values will be as follows.
User details for 1
will be printed after 1 second.User details for 2
will be printed after 2 seconds, but it will start when1
completes. So it will be printed after 3 seconds.User details for 3
will be printed after 3 seconds, but it will start when2
completes. So it will be printed after 6 seconds.User details for 4
will be printed after 4 seconds, but it will start when3
completes. So it will be printed after 10 seconds.User details for 5
will be printed after 5 seconds, but it will start when4
completes. So it will be printed after 15 seconds.