Reputation: 4701
I'm working on a watchOS timer app that needs to run for 3 1/2 minutes while showing countdown numbers. I think that I've discovered that there's nothing to do with the watch dimming- that's a system setting that the watch wearer sets for 15 or 70 seconds. But the face can update while dimmed--I see that in the native timer app for example. This is a tricky one to debug, as when the physical watch is attached to Xcode as a device, it doesn't dim or freeze the face at all. It's only when I restart the app on the physical watch that I see the issues, and there are 2:
This is what I've tried so far:
objectWillChange.send()
Here's my current code using DispatchSourceTimer and WKExtendedRuntimeSession:
class TimerManager: NSObject, ObservableObject {
@Published var phase: ExercisePhase = .notStarted
@Published var currentSet = 1
@Published var isSqueezing = true
@Published var secondsRemaining = 10
@Published var isPaused = false
private var runtimeSession: WKExtendedRuntimeSession?
private var timerSource: DispatchSourceTimer?
private var uiRefreshWorkItem: DispatchWorkItem?
func scheduleNextUpdate() {
guard !isPaused && phase != .completed && phase != .notStarted else { return }
stopSession()
// Start new session
runtimeSession = WKExtendedRuntimeSession()
runtimeSession?.start()
// Create main timer for exercise logic
let timer = DispatchSource.makeTimerSource(queue: .main)
timer.schedule(deadline: .now(), repeating: .seconds(1))
timer.setEventHandler { [weak self] in
self?.updateExercise()
}
// Create UI refresh mechanism
scheduleUIRefresh()
timerSource = timer
timer.resume()
}
private func scheduleUIRefresh() {
uiRefreshWorkItem?.cancel()
let workItem = DispatchWorkItem { [weak self] in
guard let self = self else { return }
DispatchQueue.main.async {
self.objectWillChange.send()
}
if !self.isPaused && self.phase != .completed {
self.scheduleUIRefresh()
}
}
uiRefreshWorkItem = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25, execute: workItem)
}
}
The app uses watchOS's Physical Therapy session type. The core timing functionality (including haptics) works perfectly, but the UI updates are frozen in the dimmed state at the times that I described.
I've also tried:
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true)
and
RunLoop.main.add(timer, forMode: .common)
But the same problems persist.
Has anyone encountered similar problems with watchOS UI updates in a dimmed state but with the code happily running in the background?
I'm coding in Xcode 16.2 and Swift 6.0.3 and testing on a physical Apple Watch Series 8 with watchOS 11. Any emulator I try works fine. Thanks super in advance if you can weigh in.
Upvotes: 0
Views: 32