-
-
Save czars/ebc86bcb874739fec8915e62eae3739c to your computer and use it in GitHub Desktop.
Debounce Function for Swift 3 (implemented with OperationQueue)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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