Swift Combine - Emit the latest value once per second

I have a PassthroughSubject which is connected to a ScrollView and it emits while it scrolls. I want the subject to emit the current scroll value, but only once per second. I tried throttle and debounce, but they don't seem to be doing what I need.

Like this, I can see every time it emits while I'm scrolling, so my base setup of scroll detection is working well.

scrollSubject
    .sink { value in
        print(value)
    }
    .store(in: &subscription)

But when I try to use either of these:

.throttle(for: 1, scheduler: RunLoop.main, latest: false) (tried latest: true also)`

.debounce(for: 1, scheduler: RunLoop.main)

What happens is they are not emitting while I'm scrolling, only after I've stopped it emits the latest value. How is it possible to achieve the desire behaviour?

Upvotes: 1

Views: 1664

Answers (1)

Fabio Felici
Fabio Felici

Reputation: 2916

What you are describing sounds like the sample operator available in other reactive programming libraries. It can be implemented in this way like @Alexander is describing:

extension Publisher {
  func sample(
    every interval: TimeInterval,
    on runLoop: RunLoop,
    in mode: RunLoop.Mode
  ) -> AnyPublisher<Output, Failure> {
    let timer = Timer.publish(every: interval, on: runLoop, in: mode)
      .autoconnect()
      .mapError { $0 as! Failure }

    return combineLatest(timer)
      .map(\.0)
      .eraseToAnyPublisher()
  }
}

Upvotes: 2

Related Questions