Устаревание секундомера () — SwiftUI

#ios #swift #xcode #swiftui

#iOS #swift #xcode #swiftui

Вопрос:

Я хочу, чтобы в моем приложении был секундомер, который работает полностью вне времени устройства. У меня есть приведенный ниже код, который определяет время нажатия кнопки «Пуск», а затем каждую секунду обновляет secondsElapsed значение, равное разнице между startTime текущим и текущим. Я застрял на реализации функции паузы. Если я просто аннулирую таймер обновления, то таймер перезапустится, в значительной степени продолжив работу с того места, где он остановился. Есть идеи о том, как это можно сделать?

     class StopWatchManager: ObservableObject{

    @Published var secondsElapsed = 0
    
    var startTime: Date = Date()
    
    var timer = Timer()
    
    func startWatch(){
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true){ timer in
            let current = Date()
            let diffComponents = Calendar.current.dateComponents([.second], from: self.startTime, to: current)
            let seconds = (diffComponents.second ?? 0)
            self.secondsElapsed = seconds
            
        }
        
    }
    
    func pauseWatch(){
        timer.invalidate()
    }
    
}
 

Я отображаю секундомер, используя этот код ниже:

 struct ContentView: View {
    
    @ObservedObject var stopWatchManager = StopWatchManager()
    
    var body: some View{
        HStack{
            Button("Start"){
                stopWatchManager.startWatch()
            }
            Text("(stopWatchManager.secondsElapsed)")
            Button("Pause"){
                stopWatchManager.pauseWatch()
            }
        }
    }
}
 

Ответ №1:

ДА. Вот как это сделать:

  1. При нажатии кнопки «Пауза» отметьте текущее время и вычислите прошедшее время для таймера. Аннулируйте таймер обновления.
  2. Когда таймер возобновится, возьмите текущее время и вычтите прошедшее время. Сделайте это startTime и перезапустите таймер обновления.

Вот обновленный код:

 class StopWatchManager: ObservableObject{
    
    @Published var secondsElapsed = 0
    
    var startTime: Date = Date()
    var elapsedTime = 0.0
    var paused = false
    var running = false
    
    var timer = Timer()
    
    func startWatch(){
        guard !running else { return }
        
        if paused {
            startTime = Date().addingTimeInterval(-elapsedTime)
        } else {
            startTime = Date()
        }
        paused = false
        running = true
        
        timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true){ timer in
            let current = Date()
            let diffComponents = Calendar.current.dateComponents([.second], from: self.startTime, to: current)
            let seconds = (diffComponents.second ?? 0)
            self.secondsElapsed = seconds
            
        }
        
    }
    
    func pauseWatch(){
        guard !paused else { return }
        
        timer.invalidate()
        elapsedTime = Date().timeIntervalSince(startTime)
        paused = true
        running = false
    }
    
}
 

Что следует отметить:

  • Я изменил интервал таймера на 0.1 from 1 , чтобы избежать пропуска обновлений.
  • Я добавил paused running переменные состояния и, чтобы кнопки не нажимались более одного раза подряд.

Комментарии:

1. При возобновлении работы таймера вы имеете в виду отсчет времени во время нажатия, а затем вычитание прошедшего времени? Я думаю, что меня путают имена моих переменных и ваша формулировка. Спасибо за помощь!

2. Да, потратьте время на нажатие кнопки возобновления и вычтите прошедшее время, чтобы получить новое startTime . У меня есть код, который нужно добавить к моему ответу. Прежде чем я добавлю его, какой кнопкой вы хотите отключить таймер Start или Pause ? Или, возможно Pause , следует изменить на Unpause или Resume , когда время приостановлено.

3. В моем полном приложении кнопка меняется с «Начать просмотр» на «Приостановить просмотр» (при нажатии), а затем обратно на «Начать просмотр». Поэтому я хотел бы начать снимать его с паузы

4. let diffComponents = Calendar.current.dateComponents([.second], from: self.startTime, to: current) ?? почему нет Date().timeIntervalSince(startTime) или startTime.timeIntervalSinceNow также?

5. Date().addingTimeInterval(-elapsedTime) также может быть записан как Date(timeIntervalSinceNow: -elapsedTime) или просто Date() - elapsedTime