Add throttle and debounce extensions for DispatchQueue

This commit is contained in:
Daniel Saidi 2021-09-17 16:42:06 +02:00
parent e1b0530520
commit b2a33fecc5
2 changed files with 62 additions and 0 deletions

View File

@ -13,6 +13,7 @@ This version also cleans up the code and makes changes to conform to the latest
### ✨ New features
* `Calendar+Date` has new `same` functions to provide the comparison date.
* `DispatchQueue+Throttle` has new `throttle` and `debounce` functions.
* `String+Split` has a new `split(by:)` components splitting function.
* `Url+Global` has a new `userSubscriptions` url.

View File

@ -0,0 +1,61 @@
//
// DispatchQueue+Throttle.swift
// SwiftKit
//
// Created by Daniel Saidi on 2021-09-17.
// Copyright © 2021 Daniel Saidi. All rights reserved.
//
import Foundation
private var lastDebounceCallTimes = [AnyHashable: DispatchTime]()
private let nilContext: AnyHashable = arc4random()
private var throttleWorkItems = [AnyHashable: DispatchWorkItem]()
public extension DispatchQueue {
/**
Try to perform a debounced operation.
Executes a closure and ensures that no other executions
will be made during the provided `interval`.
- parameters:
- interval: The time to delay a closure execution, in seconds
- context: The context in which the debounce should be executed
- action: The closure to be executed
*/
func debounce(interval: Double, context: AnyHashable? = nil, action: @escaping () -> Void) {
let worker = DispatchWorkItem {
defer { throttleWorkItems.removeValue(forKey: context ?? nilContext) }
action()
}
asyncAfter(deadline: .now() + interval, execute: worker)
throttleWorkItems[context ?? nilContext]?.cancel()
throttleWorkItems[context ?? nilContext] = worker
}
/**
Try to perform a throttled operation.
Performs the first performed operation, then delays any
further operations until the provided `interval` passes.
- parameters:
- interval: The time to delay a closure execution, in seconds
- context: The context in which the throttle should be executed
- action: The closure to be executed
*/
func throttle(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)
debounce(interval: interval) {
lastDebounceCallTimes.removeValue(forKey: context ?? nilContext)
}
}
}