【发布时间】:2021-12-15 15:10:05
【问题描述】:
我有一个使用DispatchQueue 的现有去抖实用程序。它接受一个闭包并在达到时间阈值之前执行它。可以这样使用:
let limiter = Debouncer(limit: 5)
var value = ""
func sendToServer() {
limiter.execute {
print("\(Date.now.timeIntervalSince1970): Fire! \(value)")
}
}
value.append("h")
sendToServer() // Waits until 5 seconds
value.append("e")
sendToServer() // Waits until 5 seconds
value.append("l")
sendToServer() // Waits until 5 seconds
value.append("l")
sendToServer() // Waits until 5 seconds
value.append("o")
sendToServer() // Waits until 5 seconds
print("\(Date.now.timeIntervalSince1970): Last operation called")
// 1635691696.482115: Last operation called
// 1635691701.859087: Fire! hello
请注意,它不是多次调用Fire!,而是在最后一次使用最后一个任务的值后 5 秒。 Debouncer 实例配置为将队列中的最后一个任务保持 5 秒,无论调用多少次。闭包传入execute(block:)方法:
final class Debouncer {
private let limit: TimeInterval
private let queue: DispatchQueue
private var workItem: DispatchWorkItem?
private let syncQueue = DispatchQueue(label: "Debouncer", attributes: [])
init(limit: TimeInterval, queue: DispatchQueue = .main) {
self.limit = limit
self.queue = queue
}
@objc func execute(block: @escaping () -> Void) {
syncQueue.async { [weak self] in
if let workItem = self?.workItem {
workItem.cancel()
self?.workItem = nil
}
guard let queue = self?.queue, let limit = self?.limit else { return }
let workItem = DispatchWorkItem(block: block)
queue.asyncAfter(deadline: .now() + limit, execute: workItem)
self?.workItem = workItem
}
}
}
如何将其转换为并发操作,以便可以如下调用:
let limit = Debouncer(limit: 5)
func sendToServer() {
await limiter.waitUntilFinished
print("\(Date.now.timeIntervalSince1970): Fire! \(value)")
}
sendToServer()
sendToServer()
sendToServer()
但是,这不会使任务去抖动,而是暂停它们直到下一个被调用。相反,它应该取消前一个任务并保持当前任务直到去抖动时间。这可以通过Swift Concurrency 完成还是有更好的方法来做到这一点?
【问题讨论】:
标签: swift grand-central-dispatch debounce swift-concurrency