import Dispatch private var throttleWorkItems = [AnyHashable: DispatchWorkItem]() private var lastDebounceCallTimes = [AnyHashable: DispatchTime]() private let nilContext: AnyHashable = arc4random() public extension DispatchQueue { /** - parameters: - deadline: The timespan to delay a closure execution - context: The context in which the throttle should be executed - action: The closure to be executed Delays a closure execution and ensures no other executions are made during deadline */ public func throttle(deadline: DispatchTime, context: AnyHashable? = nil, action: @escaping () -> Void) { let worker = DispatchWorkItem { defer { throttleWorkItems.removeValue(forKey: context ?? nilContext) } action() } asyncAfter(deadline: deadline, execute: worker) throttleWorkItems[context ?? nilContext]?.cancel() throttleWorkItems[context ?? nilContext] = worker } /** - parameters: - interval: The interval in which new calls will be ignored - context: The context in which the debounce should be executed - action: The closure to be executed Executes a closure and ensures no other executions will be made during the interval. */ public func debounce(interval: Double, context: AnyHashable? = nil, action: @escaping () -> Void) { if let last = lastDebounceCallTimes[context ?? nilContext], last + interval > .now() { return } lastDebounceCallTimes[context ?? nilContext] = .now() async(execute: action) // Cleanup & release context throttle(deadline: .now() + interval) { lastDebounceCallTimes.removeValue(forKey: context ?? nilContext) } } }