防抖
import UIKit
class Debouncer {
private let label: String
private let interval: Int
private let queue: DispatchQueue
private var workItem: DispatchWorkItem?
private var lock: DispatchSemaphoreWrapper
/// interval: 单位毫秒
init(label: String = "PZDebouncer", interval: Int = 500) {
self.label = label
self.interval = interval
self.queue = DispatchQueue(label: label)
self.lock = DispatchSemaphoreWrapper(value: 1)
}
func call(_ callback: @escaping (() -> ())) {
self.lock.sync {
self.workItem?.cancel()
self.workItem = DispatchWorkItem {
callback()
}
if let workItem = self.workItem {
self.queue.asyncAfter(deadline: .now() + DispatchTimeInterval.milliseconds(interval), execute: workItem)
}
}
}
}
struct DispatchSemaphoreWrapper {
private var lock: DispatchSemaphore
init(value: Int) {
self.lock = DispatchSemaphore(value: 1)
}
func sync(execute: () -> ()) {
_ = lock.wait(timeout: DispatchTime.distantFuture)
lock.signal()
execute()
}
}
节流
//
// Throttle.swift
import UIKit
class Throttle {
private let label: String
private let interval: Int
private let queue: DispatchQueue
private var workItem: DispatchWorkItem?
private var lock: DispatchSemaphoreWrapper
private var lastTime: Date = Date()
/// interval: 单位毫秒
init(label: String = "Debouncer", interval: Int = 500) {
self.label = label
self.interval = interval
self.queue = DispatchQueue(label: label)
self.lock = DispatchSemaphoreWrapper(value: 1)
}
func call(_ callback: @escaping (() -> ())) {
self.lock.sync {
self.workItem?.cancel()
self.workItem = DispatchWorkItem { [weak self] in
self?.lastTime = Date()
callback()
}
if let workItem = self.workItem {
let new = Date()
let delay = new.timeIntervalSince1970 - lastTime.timeIntervalSince1970 > Double(self.interval)/1000 ? DispatchTimeInterval.milliseconds(0) : DispatchTimeInterval.milliseconds(self.interval)
self.queue.asyncAfter(deadline: .now() + delay, execute: workItem)
}
}
}
}
使用
//
// ViewController.swift
// 防抖和节流
import UIKit
class ViewController: UIViewController {
let throttle = Throttle(label: "123", interval: 2000)
let debouncer = Debouncer(label: "123", interval: 2000)
override func viewDidLoad() {
super.viewDidLoad()
// testThrottle()
testDebouncer()
}
func testThrottle() {
for _ in 0..<10 {
sleep(1)
throttle.call {
let date = Date()
print("XQ:\(date.timeIntervalSince1970)")
}
}
}
func testDebouncer() {
for i in 0..<100 {
let delay = i % 2 == 0 ? 1 : 3
sleep(UInt32(delay))
debouncer.call {
let date = Date()
print("XQ:\(date.timeIntervalSince1970)")
}
}
}
}