HaishinKit.swift/Sources/Util/TimerDriver.swift

81 lines
2.1 KiB
Swift

import Foundation
public protocol TimerDriverDelegate: class {
func tick(_ driver: TimerDriver)
}
// MARK: -
public class TimerDriver: NSObject {
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 weak var timer: Timer? {
didSet {
if let oldValue: Timer = oldValue {
oldValue.invalidate()
}
if let timer: Timer = timer {
RunLoop.current.add(timer, forMode: .commonModes)
}
}
}
public override var description: String {
return Mirror(reflecting: self).description
}
public func setDelegate(_ delegate: TimerDriverDelegate, withQueue: DispatchQueue? = nil) {
self.delegate = delegate
self.queue = withQueue
}
@objc 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 running: Bool {
return runloop != nil
}
final public func startRunning() {
DispatchQueue.global(qos: .userInteractive).async {
if let _ = self.runloop {
return
}
self.timer = Timer(
timeInterval: 0.0001, target: self, selector: #selector(on(timer: )), userInfo: nil, repeats: true
)
self.nextFire = mach_absolute_time() + self.interval
self.delegate?.tick(self)
self.runloop = .current
self.runloop?.run()
}
}
final public func stopRunning() {
guard let runloop: RunLoop = runloop else {
return
}
timer = nil
CFRunLoopStop(runloop.getCFRunLoop())
self.runloop = nil
}
}