Skip to content

Instantly share code, notes, and snippets.

@MichaelJBerk
Created March 17, 2026 19:48
Show Gist options
  • Select an option

  • Save MichaelJBerk/7e04631ae6c9f480b6ff27a0f1ee4f08 to your computer and use it in GitHub Desktop.

Select an option

Save MichaelJBerk/7e04631ae6c9f480b6ff27a0f1ee4f08 to your computer and use it in GitHub Desktop.
A property wrapper that adds a delay when setting the underlying value When setting the value to nil, this property wrapper adds a delay before the value can be changed again. This is useful to avoid certain UI bugs that can occur when changing selection too quickly
///A property wrapper that adds a delay when setting the underlying value
///
///When setting the value to nil, this property wrapper adds a delay before the value can be changed again. This is useful to avoid certain UI bugs that can occur when changing selection too quickly
@propertyWrapper @Observable
final class SelectionDelay<Value: Identifiable & Equatable> {
private var allowSelection = true
private var baseValue: Value?
private var timer: Timer?
private let delay: TimeInterval
/// Create a new instance of Selection Delay
/// - Parameters:
/// - wrappedValue: The underlying value to get/set
/// - delay: The delay before the value can be set again
init(wrappedValue: Value? = nil, delay: TimeInterval = 0.01) {
self.baseValue = wrappedValue
self.delay = delay
}
var wrappedValue: Value? {
get { baseValue }
set {
if newValue == nil, baseValue != nil {
baseValue = nil
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { _ in
self.allowSelection = true
}
} else {
if allowSelection {
baseValue = newValue
allowSelection = false
}
}
}
}
var projectedValue: Binding<Value?> {
Binding(
get: { self.wrappedValue },
set: { self.wrappedValue = $0 }
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment