Skip to content

Instantly share code, notes, and snippets.

@twittemb
Last active September 3, 2022 17:04
Show Gist options
  • Save twittemb/47f8fa0950d44749a0d328afb8a2584c to your computer and use it in GitHub Desktop.
Save twittemb/47f8fa0950d44749a0d328afb8a2584c to your computer and use it in GitHub Desktop.
extension DispatchTimeInterval {
var nanoseconds: UInt64 {
switch self {
case .nanoseconds(let value) where value >= 0: return UInt64(value)
case .microseconds(let value) where value >= 0: return UInt64(value) * 1000
case .milliseconds(let value) where value >= 0: return UInt64(value) * 1_000_000
case .seconds(let value) where value >= 0: return UInt64(value) * 1_000_000_000
case .never: return .zero
default: return .zero
}
}
}
final class UncheckedSendable<Value>: @unchecked Sendable {
var storage: Value
let lock = NSRecursiveLock()
init(_ value: Value) {
self.storage = value
}
var value: Value {
get {
defer { self.lock.unlock() }
self.lock.lock()
return self.storage
}
set {
defer { self.lock.unlock() }
self.lock.lock()
self.storage = newValue
}
}
}
#if canImport(SwiftUI)
import SwiftUI
extension Binding {
struct DueValue {
let value: Value
let dueTime: DispatchTime
}
public func debounce(for dueTime: DispatchTimeInterval) -> Self {
let lastKnownValue = UncheckedSendable<DueValue?>(nil)
let debouncing = UncheckedSendable(false)
return Binding {
self.wrappedValue
} set: { value in
if debouncing.value {
let newValue = DueValue(value: value, dueTime: DispatchTime.now().advanced(by: dueTime))
lastKnownValue.value = newValue
} else {
debouncing.value = true
Task {
var timeToSleep = dueTime.nanoseconds
var currentValue = value
repeat {
lastKnownValue.value = nil
try? await Task.sleep(nanoseconds: timeToSleep)
if let lastKnownValue = lastKnownValue.value {
timeToSleep = DispatchTime.now().distance(to: lastKnownValue.dueTime).nanoseconds
currentValue = lastKnownValue.value
}
} while lastKnownValue.value != nil
debouncing.value = false
self.wrappedValue = currentValue
}
}
}
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment