Search code examples
iosswifttimerswiftuicountdown

SwiftUI - Timer doesn't stop at 0


I have a timer that counts down from a specific day to the current date but the problem I'm facing is that the timer doesn't stop when it reaches 00:00:00

I followed this tutorial

@State var currentDate: Date = Date()
var timer: Timer {
    Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (_) in
        self.currentDate = Date()
    }
}

var endDate = Calendar.current.date(byAdding: .minute, value: 1, to: Date())!

var body: some View {
    Text(countdownString(to: endDate))
        .font(.headline)
        .fontWeight(.bold)
        .foregroundColor(.green)
        .onAppear {
            _ = self.timer
            if self.endDate == self.currentDate {
                self.timer.invalidate()
            }
    }
}



func countdownString(to date: Date) -> String {
    let calendar = Calendar(identifier: .gregorian)
    let components = calendar.dateComponents([.hour, .minute, .second], from: currentDate, to: endDate)
    return String(format: "%02d hours : %02d minutes : %02d seconds",
                  components.hour ?? 00,
                  components.minute ?? 00,
                  components.second ?? 00)
}

Solution

  • Set the timer in the onAppear and invalidate the timer when endDate and currentDate align together.

    struct CV: View {
        @State var currentDate: Date = Date()
        @State var timer: Timer?
    
        var endDate = Calendar.current.date(byAdding: .minute, value: 1, to: Date())!
    
        var body: some View {
            Text(countdownString(to: endDate))
                .font(.headline)
                .fontWeight(.bold)
                .foregroundColor(.green)
                .onAppear {
                    self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                        self.currentDate = Date()
                    }
            }
        }
    
        func countdownString(to date: Date) -> String {
            let calendar = Calendar(identifier: .gregorian)
            let components = calendar.dateComponents([.hour, .minute, .second], from: currentDate, to: endDate)
            if currentDate >= endDate {
                timer?.invalidate()
                timer = nil
            }
            return String(format: "%02d hours : %02d minutes : %02d seconds",
                          components.hour ?? 00,
                          components.minute ?? 00,
                          components.second ?? 00)
        }
    }