skip to Main Content

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()
  }

2

Answers


  1. Chosen as BEST ANSWER

    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)
    

  2. You can use the flatMap operator to transform a publisher or value into a new publisher in the Combine chain. For example:

    class ViewModel : ObservableObject {
        var cancellable : AnyCancellable?
        
        init() {
            cancellable = Just(1).flatMap { _ in
                Timer
                  .publish(every: 2, on: .main, in: .default)
                  .autoconnect()
            }.sink { value in
                print("Publisher fired: (value)")
            }
        }
    }
    

    You would replace my trivial Just(1) publisher with your messagesPublisher

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search