76 lines
1.9 KiB
Swift
76 lines
1.9 KiB
Swift
import Foundation
|
|
|
|
public protocol TimerDriverDelegate: AnyObject {
|
|
func tick(_ driver: TimerDriver)
|
|
}
|
|
|
|
// MARK: -
|
|
public class TimerDriver {
|
|
public var interval: UInt64 = MachUtil.nanosToAbs(10 * MachUtil.nanosPerMsec)
|
|
|
|
var queue: DispatchQueue?
|
|
weak var delegate: TimerDriverDelegate?
|
|
|
|
private var runloop: RunLoop?
|
|
private var nextFire: UInt64 = 0
|
|
private var timer: Timer? {
|
|
didSet {
|
|
oldValue?.invalidate()
|
|
timer.map {
|
|
RunLoop.current.add($0, forMode: RunLoop.Mode.common)
|
|
}
|
|
}
|
|
}
|
|
|
|
public func setDelegate(_ delegate: TimerDriverDelegate, withQueue: DispatchQueue? = nil) {
|
|
self.delegate = delegate
|
|
self.queue = withQueue
|
|
}
|
|
|
|
@objc
|
|
private func on(timer: Timer) {
|
|
guard nextFire <= mach_absolute_time() else {
|
|
return
|
|
}
|
|
if let queue: DispatchQueue = queue {
|
|
queue.sync {
|
|
self.delegate?.tick(self)
|
|
}
|
|
} else {
|
|
delegate?.tick(self)
|
|
}
|
|
nextFire += interval
|
|
}
|
|
}
|
|
|
|
extension TimerDriver: Running {
|
|
// MARK: Running
|
|
public var isRunning: Atomic<Bool> {
|
|
.init(runloop != nil)
|
|
}
|
|
|
|
public func startRunning() {
|
|
DispatchQueue.global(qos: .userInteractive).async {
|
|
guard self.runloop == nil else {
|
|
return
|
|
}
|
|
self.timer = Timer(
|
|
timeInterval: 0.0001, target: self, selector: #selector(self.on), userInfo: nil, repeats: true
|
|
)
|
|
self.nextFire = mach_absolute_time() + self.interval
|
|
self.delegate?.tick(self)
|
|
self.runloop = .current
|
|
self.runloop?.run()
|
|
}
|
|
}
|
|
|
|
public func stopRunning() {
|
|
guard let runloop: RunLoop = runloop else {
|
|
return
|
|
}
|
|
timer = nil
|
|
CFRunLoopStop(runloop.getCFRunLoop())
|
|
self.runloop = nil
|
|
}
|
|
}
|