I want to debounce a batch of events and process them after a delay of ~1.5 seconds. Here's what I've done.
class ViewModel: ObservableObject {
@Published var pending: [TaskInfo]
private var cancellable: AnyCancellable? = nil
init() {
processPendingTasks()
}
func queueTask(task: TaskInfo) {
pending.append(task)
}
private func processPendingTasks() {
cancellable = $pendingTasks
.debounce(for: 1.5, scheduler: RunLoop.main)
.sink(receiveValue: { batch in
// Iterate though elements and process events.
})
}
}
Issue: This works fine, but the issue that I've is that it performs unnecessary view updates since the array is tagged @Published
.
What I'm looking for: The ideal approach would be a streaming setup where I get all events (in a batched fashion) but the sink
should wait exactly for 1.5 seconds after the last event was added.
I tried PassthroughSubject
, but it seems like it only gets me the last event that happened in the last 1.5 seconds.
CodePudding user response:
A possible solution is a combination of a PassthroughSubject
and the collect
operator. In queueTask
send the tasks to the subject.
func queueTask(task: TaskInfo) {
subject.send(task)
}
1.5 seconds after receiving the last item send
subject.send(completion: .finished)
and subscribe
subject
.collect()
.sink { [weak self] tasks in
self?.pending = tasks
}
If the interval of the incoming tasks is < 1.5 seconds you could also use the .timeout(1.5)
operator which terminates the pipeline after the timeout interval.