Home > Software design >  SwiftUI: When using a timer, will the average execution per time stay constant?
SwiftUI: When using a timer, will the average execution per time stay constant?

Time:09-24

I'm currently developing an app that has a timer element built into it. So if a user selects 30 minutes, the app will display the time remaining -- 29:59, one second later 29:58, 29:57, etc. The timer can be active for a few hours at a time. After some research, I've found that people have said the timer isn't that accurate and shouldn't be used for "highly precise timekeeping"? So I'm not exactly sure what this would entail. Would the average rate at which the timer executes over a certain amount of time still remain constant after a few hours? For example, if I set a timer to add 1 to an integer every second, would the integer value be 14,400 (give or take about /-10) after 4 hours (since there are 14,400 seconds in 4 hours)?

import SwiftUI

struct ContentView: View {
    @State var timeElapsed = 0
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var body: some View {
        VStack{
            Text(String(timeElapsed)) //Would this display 14400 after 4 hours?
        }
        .onReceive(timer) { _ in
            timeElapsed  = 1
        }
    }
}

CodePudding user response:

No. There is no promise that this will be called every second. In particular, your app may be put into the background and this timer will not be called. (Over 4 hours, this is almost certain.) Timers do not accumulate missed calls. They just skip them.

The way you implement a timer is to subtract the start time from the current time, not try to accumulate seconds. You want something more like this (untested):

struct ContentView: View {
    @State var timeElapsed = 0
    @State var startTime = Date()
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var body: some View {
        VStack{
            Text(String(timeElapsed)) //Would this display 14400 after 4 hours?
        }
        .onReceive(timer) { _ in
            timeElapsed = Int(-startTime.timeIntervalSinceNow)
        }
        .onAppear { startTime = Date() }
    }
}

CodePudding user response:

There is also an iOS 15 approach

import SwiftUI

@available(iOS 15.0, *)
struct NewTimerView: View {
    let startDate: Date = Date()
    var body: some View {
        //A view that updates according to a schedule that you provide
        TimelineView(.periodic(from: startDate, by: 1), content: {context in
            Text((-startDate.timeIntervalSinceNow.rounded()).description)
        })
    }
}

https://developer.apple.com/documentation/swiftui/timelineview

The workout app code along from WWDC gloses over it https://developer.apple.com/wwdc21/10009

  • Related