Issue #376

https://github.com/onmyway133/Omnia/blob/master/Sources/Shared/Debouncer.swift

import Foundation

public class Debouncer {
    private let delay: TimeInterval
    private var workItem: DispatchWorkItem?

    public init(delay: TimeInterval) {
        self.delay = delay
    }

    /// Trigger the action after some delay
    public func run(action: @escaping () -> Void) {
        workItem?.cancel()
        workItem = DispatchWorkItem(block: action)
        DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: workItem!)
    }
}
import XCTest

class DebouncerTests: XCTestCase {

    func testDebounce() {
        let expectation = self.expectation(description: #function)
        let debouncer = Debouncer(delay: 0.5)
        var value = 0

        debouncer.run(action: {
            value = 1
        })

        debouncer.run(action: {
            value = 2
        })

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: {
            debouncer.run(action: {
                value = 3
            })
        })

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.71, execute: {
            XCTAssertEqual(value, 3)
            expectation.fulfill()
        })

        wait(for: [expectation], timeout: 1.2)
    }
}