A parte central do meu App é um timer. Até agora, este foi o Código (retirado do Codebase principal para ser o mínimo reproduzível):
import SwiftUI
struct TestView: View {
@State var countdownTimer = 5 * 60 /// The actual seconds of the timer, being counted down/up
@State var timerRunning = false /// Var to set and see if timer is running
var body: some View {
/// For formatting the timer numbers
let style = Duration.TimeFormatStyle(pattern: .minuteSecond)
let formTimer = Duration.seconds(countdownTimer).formatted()
let formTimerShort = Duration.seconds(countdownTimer).formatted(style)
/// The main Timer If there are no hours we hide the hour number and make the timer bigger in this way.
Text(countdownTimer / 3600 == 0 && timerRunning ? "\(formTimerShort)" : "\(formTimer)")
.onReceive(Timer.publish(every: 1, on: .main, in: .common).autoconnect()) { _ in
if countdownTimer > 0 && timerRunning {
countdownTimer -= 1
} else {
timerRunning = false
}
}
/// The Start and Pause buttons
HStack {
if !timerRunning {
Button(action: {
timerRunning = true
}) {
Text("Start")
.frame(width: 300, height: 75)
.font(.system(size: 60))
}
} else {
Button(action: {
timerRunning = false
}) {
Text("Pause")
.frame(width: 300, height: 75)
.font(.system(size: 60))
}
}
}
}
}
#Preview {
TestView()
}
O problema com isso era que não era preciso. Cerca de 40 segundos em 1 hora de uso do timer. Então minha ideia era mudar quando o Timer é publicado de 1 para 0,001, aumentando assim a resolução. Este Código funciona, mas é ainda menos preciso!
struct TestView: View {
@State var countdownTimer = 5 * 60 /// The actual seconds of the timer, being counted down/up
@State private var fractionTimer = 0 /// Helping us to make the timer more accurate
@State var timerRunning = false /// Var to set and see if timer is running
var body: some View {
[...]
/// The main Timer If there are no hours we hide the hour number and make the timer bigger in this way.
Text(countdownTimer / 3600 == 0 && timerRunning ? "\(formTimerShort)" : "\(formTimer)")
.onReceive(Timer.publish(every: 0.001, on: .main, in: .common).autoconnect()) { _ in
/// Count up the fraction timer, only if he hits a certain Number we count up our Visible Timer
if timerRunning {
fractionTimer += 1
}
if fractionTimer == 1000 {
if countdownTimer > 0 && timerRunning {
countdownTimer -= 1
fractionTimer = 0
} else {
timerRunning = false
fractionTimer = 0
}
}
}
[...]
}
}
De acordo com minha lógica, isso deveria ter tirado a imprecisão de 40 segundos por hora para 0,04 segundos por hora. Mas, na verdade, agora está 120 segundos por hora fora!
Como isso pode ser? É porque ele está rodando no thread principal e porque ele é chamado 1000 vezes por segundo, há muitas outras tarefas que atrasam essa chamada? Devo tirá-lo do thread principal?