Reactive Programming in iOS with Combine, Episode 8: More Transforming Operators | Kodeco, the new raywenderlich.com

Learn about how the scan and flatMap operators can be used in your code to do more advanced transformations.


This is a companion discussion topic for the original entry at https://www.kodeco.com/5429795-reactive-programming-in-ios-with-combine/lessons/8

Hi Team,

For some reason I find flatMap operator to be really confusing. While trying to get it, I’ve asked ChatGPT to challenge me with a flatMap problem, and this is the challenge it gave me, which I found rather interesting:

// Create a publisher that:
// 1. Emits a string "First" after 0.5 seconds
// 2. Emits an integer 1 after 1 second
// 3. Emits a string "Second" after 1.5 seconds
// 4. Emits an integer 2 after 2 seconds
// 5. Completes after 2.5 seconds
//
// Then, create a subscriber that:
// 1. Prints each received value
// 2. Marks the completion of the subscription when the publisher completes

However, while it was decent giving me a challenge, it can’t seem to be able to figure out how to solve it itself and after an hour of fiddling around I’m stuck as well.

Here is the latest variation I ended up with:

import PlaygroundSupport
import Combine

PlaygroundPage.current.needsIndefiniteExecution = true

var strings = PassthroughSubject<String, Never>()
var numbers = PassthroughSubject<Int, Never>()

var subject = PassthroughSubject<AnyPublisher<Any, Never>, Never>()
var subscriptions = Set<AnyCancellable>()

subject
  .flatMap { $0 }
  .delay(for: 0.5, scheduler: RunLoop.main)
  .print()
  .sink(receiveCompletion: { _ in
    print("Completed")
  }, receiveValue: { value in
    print(value)
  })
  .store(in: &subscriptions)

subject.send(strings.map {$0 as Any}.eraseToAnyPublisher())
subject.send(numbers.map {$0 as Any}.eraseToAnyPublisher())
strings.send("First")
numbers.send(1)
strings.send("Second")
numbers.send(2)
subject.send(completion: .finished)

The problem is that it delays all of the events for 0.5 seconds and then emits all of them at the same time. But the challenge is asking to add a 0.5 seconds delay between each event. I can’t seem to find a solution to that. I’ve looks at debounce, but debounce would drop events, I’ve looked at throttle, but it also drops the events. I’ve looked at adding the Timer publisher inside of the FlatMap, but that also emits all of the events at the same time.

Can you think of any other recommendations?