I wrote a pseudo real-time simulation MacOS app that uses an NSTimer. I'd like to run the app for hours or possibly days. My problem is the app doesn't run in real-time when the screensaver turns on, the computer goes to sleep, or the monitor is off. When I use an app to prevent the computer/display from going to sleep and a "Hot Corner" to disable the screensaver, the app runs in real-time as expected.
Here are steps to reproduce the issue
- Create a new MacOS "App" project
- Replace the fcode in ViewController.swift with the following code
- Run the app
- Activate the screensaver or turn off the monitor
class ViewController: NSViewController {
var startTime:Date?
override func viewDidLoad() {
super.viewDidLoad()
var maxValue:TimeInterval = -1e20
// Create a Timer that fires every second
let timer = Timer(timeInterval: 1, repeats: true) { [weak self] _ in
if let delta = self?.startTime?.timeIntervalSinceNow {
let value = abs(delta)
if value > maxValue {
maxValue = value
}
print("delta: \(value) max: \(maxValue)")
}
self?.startTime = Date()
}
RunLoop.current.add(timer, forMode: RunLoop.Mode.default)
}
}
The closure code should fire once per second. With the screensaver on, the code executes about once every 11 seconds.
From Apple's NSTimer documentation,
A timer is not a real-time mechanism. If a timer’s firing time occurs during a long run loop callout or while the run loop is in a mode that isn't monitoring the timer, the timer doesn't fire until the next time the run loop checks the timer. Therefore, the actual time at which a timer fires can be significantly later
Question: Does anyone know how to create a time-based app that fires at the same rate with the screensaver on or the monitor off?
OS: MacOS 10.15.3, SDK: Xcode 11.3