Skip to content

Instantly share code, notes, and snippets.

@cbess
Last active December 6, 2022 09:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cbess/8242e2b7f726a3075ea4d07cdba8e284 to your computer and use it in GitHub Desktop.
Save cbess/8242e2b7f726a3075ea4d07cdba8e284 to your computer and use it in GitHub Desktop.
Swift DispatchQueue throttle and debounce class (thread-safe)
//
// DispatchQueueDelay.swift
//
// Created by C. Bess on 9/17/19.
// MIT - Soli Deo gloria - perfectGod.com
//
// refs:
// - https://gist.github.com/fjcaetano/ff3e994c4edb4991ab8280f34994beb4
// - https://www.craftappco.com/blog/2018/5/30/simple-throttling-in-swift
import Dispatch
class DispatchQueueDelay {
private var throttleWorkItem: DispatchWorkItem?
private var lastDebounceCallTime: DispatchTime?
/**
Delays a closure execution and ensures no other executions are made during deadline
- parameters:
- deadline: The timespan to delay a closure execution
- queue: The `DispatchQueue` to use. Default to `main`.
- action: The closure to be executed
*/
public func throttle(deadline: DispatchTime, queue: DispatchQueue = .main, action: @escaping () -> Void) {
let worker = DispatchWorkItem { [weak self] in
defer { self?.throttleWorkItem = nil }
action()
}
queue.asyncAfter(deadline: deadline, execute: worker)
throttleWorkItem?.cancel()
throttleWorkItem = worker
}
/**
Executes a closure and ensures no other executions will be made during the interval.
- parameters:
- interval: The interval in which new calls will be ignored
- queue: The `DispatchQueue` to use. Default to `main`.
- action: The closure to be executed
*/
public func debounce(interval: DispatchTimeInterval, queue: DispatchQueue = .main, action: @escaping () -> Void) {
if let last = lastDebounceCallTime, last + interval > .now() {
return
}
lastDebounceCallTime = .now()
queue.async(execute: action)
// cleanup
throttle(deadline: .now() + interval) { [weak self] in
self?.lastDebounceCallTime = nil
}
}
}
@cbess
Copy link
Author

cbess commented Sep 25, 2019

Examples

Throttle:

throttleSomeTask.throttle(deadline: .now() + DispatchTimeInterval.seconds(3)) { [weak self] in
  self?.someTask()
}

Debounce:

debounceSomeTask.debounce(interval: .seconds(Int(delaySecs))) {
  self.someTask()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment