mirror of
https://github.com/coteditor/CotEditor.git
synced 2024-09-11 19:27:30 +03:00
Migrate Debouncer to Task-based
This commit is contained in:
parent
c984f9cedd
commit
1126a3c5eb
@ -23,26 +23,15 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Dispatch
|
||||
|
||||
extension DispatchTimeInterval {
|
||||
|
||||
static func seconds(_ interval: Double) -> DispatchTimeInterval {
|
||||
|
||||
.milliseconds(Int(interval * 1000))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Object invoking the registered block when a specific time interval is passed after the last call.
|
||||
final class Debouncer {
|
||||
@MainActor final class Debouncer {
|
||||
|
||||
// MARK: Private Properties
|
||||
|
||||
private let action: () -> Void
|
||||
private let defaultDelay: DispatchTimeInterval
|
||||
private let action: @MainActor @Sendable () -> Void
|
||||
private let defaultDelay: ContinuousClock.Duration
|
||||
|
||||
private var currentWorkItem: DispatchWorkItem?
|
||||
private var task: Task<Void, any Error>?
|
||||
|
||||
|
||||
|
||||
@ -53,7 +42,7 @@ final class Debouncer {
|
||||
/// - Parameters:
|
||||
/// - delay: The default time to wait since last call.
|
||||
/// - action: The action to debounce.
|
||||
init(delay: DispatchTimeInterval = .seconds(0), action: @escaping () -> Void) {
|
||||
init(delay: ContinuousClock.Duration = .seconds(0), action: @MainActor @Sendable @escaping () -> Void) {
|
||||
|
||||
self.action = action
|
||||
self.defaultDelay = delay
|
||||
@ -61,51 +50,54 @@ final class Debouncer {
|
||||
|
||||
|
||||
deinit {
|
||||
self.cancel()
|
||||
Task { [task] in
|
||||
task?.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: Public Methods
|
||||
|
||||
/// Invokes the action after when `delay` time have passed since last call.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - delay: The time to wait for fire. If nil, receiver's default delay is used.
|
||||
func schedule(delay: DispatchTimeInterval? = nil) {
|
||||
func schedule(delay: ContinuousClock.Duration? = nil) {
|
||||
|
||||
let delay = delay ?? self.defaultDelay
|
||||
let workItem = DispatchWorkItem { [weak self] in
|
||||
|
||||
self.task?.cancel()
|
||||
self.task = Task { [weak self] in
|
||||
try await Task.sleep(for: delay)
|
||||
|
||||
self?.action()
|
||||
self?.currentWorkItem = nil
|
||||
self?.task = nil
|
||||
}
|
||||
|
||||
self.cancel()
|
||||
self.currentWorkItem = workItem
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: workItem)
|
||||
}
|
||||
|
||||
|
||||
/// Performs the action immediately.
|
||||
func perform() {
|
||||
|
||||
self.currentWorkItem?.cancel()
|
||||
DispatchQueue.main.async(execute: self.action)
|
||||
self.cancel()
|
||||
self.action()
|
||||
}
|
||||
|
||||
|
||||
/// Performs the action immediately if scheduled.
|
||||
func fireNow() {
|
||||
|
||||
self.currentWorkItem?.perform()
|
||||
guard self.task != nil else { return }
|
||||
|
||||
self.cancel()
|
||||
self.action()
|
||||
}
|
||||
|
||||
|
||||
/// Cancels the action if scheduled.
|
||||
func cancel() {
|
||||
|
||||
self.currentWorkItem?.cancel()
|
||||
self.currentWorkItem = nil
|
||||
self.task?.cancel()
|
||||
self.task = nil
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ struct DebouncerTests {
|
||||
|
||||
@Test func debounce() async throws {
|
||||
|
||||
try await confirmation("Debouncer executed", expectedCount: 1) { confirm in
|
||||
try await confirmation("Debouncer executed", expectedCount: 1) { @MainActor confirm in
|
||||
let debouncer = Debouncer(delay: .seconds(0.5)) {
|
||||
confirm()
|
||||
}
|
||||
@ -43,7 +43,7 @@ struct DebouncerTests {
|
||||
}
|
||||
|
||||
|
||||
@Test func immediateFire() {
|
||||
@MainActor @Test func immediateFire() {
|
||||
|
||||
var value = 0
|
||||
let debouncer = Debouncer {
|
||||
@ -65,7 +65,7 @@ struct DebouncerTests {
|
||||
|
||||
@Test func cancel() async {
|
||||
|
||||
await confirmation("Debouncer cancelled", expectedCount: 0) { confirm in
|
||||
await confirmation("Debouncer cancelled", expectedCount: 0) { @MainActor confirm in
|
||||
let debouncer = Debouncer {
|
||||
confirm()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user