Search code examples
iosswiftcombine

How to fire one publisher after another?


I have two publishers, one that gathers messages based on a state, and the second which is a Timer. I want these to fire in order - so first gather data, then start a timer. How can I do this? This is my current code:

let messagesPublisher = OnboardingStateLogic.publisher(
  forState: state,
  nextState: nextState
)

messagesPublisher
  .sink { completion in 
    print("completed")
  } receiveValue: { [weak self] messages in
    messages.forEach { message in
      self?.queue.enqueue(message)
    }
  }

timer = Timer
  .publish(every: 2, on: .main, in: .default)
  .autoconnect()
  .sink { _ in
    self.dequeueMessages()
  }

Solution

  • I ended up using Publishers.Zip. This only publishes when both upstream publishers have outputted a value:

    messagesPublisher.sink(
      receiveCompletion: { _ in },
      receiveValue: { [weak self] message in
       self?.queue.enqueue(message)
      }
    ).store(in: &cancellables)
    
    let delayPublisher = Timer
      .publish(every: 2, on: .main, in: .default)
      .autoconnect()
      .eraseToAnyPublisher()
      .setFailureType(to: Error.self)
    
    let delayedValuesPublisher = Publishers.Zip(messagesPublisher, delayPublisher).eraseToAnyPublisher()
    
    delayedValuesPublisher.sink(
      receiveCompletion: { completion in
        switch completion {
        case .failure(let error):
          print("something went wrong", error)
        case .finished:
          break
        }
      },
      receiveValue: { [weak self] _ in
        self?.dequeueMessages()
      }
    ).store(in: &cancellables)