Skip to content

Instantly share code, notes, and snippets.

@DoubleREW
Last active March 15, 2021 02:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save DoubleREW/567f5e67262f1de781f4f9164235d4e9 to your computer and use it in GitHub Desktop.
Save DoubleREW/567f5e67262f1de781f4f9164235d4e9 to your computer and use it in GitHub Desktop.
Debounce Function for Swift 3 (implemented with OperationQueue)
extension OperationQueue {
/// Creates a debounced function that delays invoking `action` until after `delay` seconds have elapsed since the last time the debounced function was invoked.
///
/// - Parameters:
/// - delay: The number of seconds to delay.
/// - underlyingQueue: An optional background queue to run the function
/// - action: The function to debounce.
/// - Returns: Returns the new debounced function.
open class func debounce(delay: TimeInterval, underlyingQueue: DispatchQueue? = nil, action: @escaping () -> Void) -> (() -> Void) {
// Init a new serial queue
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
queue.underlyingQueue = underlyingQueue
let sleepOpName = "__SleepOp" // Sleep operation name
let actionOpName = "__ActionOp" // Action operation name
return {
// Check if the first not cancelled or finished operation is executing
var isExecuting = false
for op in queue.operations {
if op.isFinished || op.isCancelled {
continue
}
isExecuting = op.isExecuting && op.name == actionOpName
break
}
// print("isExecuting: \(isExecuting), count: \(queue.operations.count)")
if !isExecuting {
queue.cancelAllOperations()
}
let sleepOp = BlockOperation(block: {
Thread.sleep(forTimeInterval: delay)
})
sleepOp.name = sleepOpName
let actionOp = BlockOperation(block: {
action()
})
actionOp.name = actionOpName
queue.addOperation(sleepOp)
queue.addOperation(actionOp)
}
}
}
func testDebounce() {
var gi = 0
let queue = DispatchQueue.global(qos: .default)
let debounced = OperationQueue.debounce(delay: 0.2, underlyingQueue: queue) {
print("Fired: \(gi)")
}
for i in 0...9 {
let r = Double(Int(arc4random()) % 2)
let s = 0.1 + (0.2 * r)
print("Run: \(i) (sleep for \(s)s)")
gi = i
debounced()
Thread.sleep(forTimeInterval: s)
}
}
testDebounce()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment