I want to transition from Combine to the Observation framework my question is how do I Debounce user input with the Observation framework there appears now way to do this. Any and all help is welcomed.
Replies
The expected path forward here is to combine (hey hey!) two tasks:
-
Turning an observed property into an async sequence of value changes.
-
Debouncing such a sequence.
The second task is covered by Swift Async Algorithms. The first task, however, is a challenge. The original SE-0395 proposed a general way to do this but that ran into problems during review. The proposal was recently accept with the async stuff moved into the Future Directions section.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Thanks Eskimo, could you point me in a direction for the first point above ? Where do I start to turn an observed property into an async sequence of value changes ? Thanks, A
@Dionysus-Design If you just want to debounce, you can use this code :
public actor Debouncer {
private let duration: Duration
private var isPending = false
public init(duration: Duration) {
self.duration = duration
}
public func sleep() async -> Bool {
if isPending { return false }
isPending = true
try? await Task.sleep(for: duration)
isPending = false
return true
}
}
Put this code in your Observable:
private let debouncer = Debouncer(duration: .seconds(0.5))
func checkEmailValidity() async {
guard await debouncer.sleep() else { return }
... do your debounced stuff here ...
}
And somewhere on your SwiftUI View for example:
.onChange(of: viewModel.email) { Task { await viewModel.checkEmailValidity() } }
-
This is a more like a throttle, not a debounce. We need to reset the timer each time a new event is emitted, replace the last occurrence and then try to wait for the new timer to complete.
It seems that the timer is only set on the first key stroke. How would I reset timer to zero on each stroke to better implement debounce?