Alexander A
Alexander A

Reputation: 57

Stopwatch iOS Swift

I am writing a stopwatch application for timekeeping and I need to check if the clock is over a certain time interval (like 20:00 - 06:00) and in that case add the current elapsed time to a TimeInterval variable that I later will store in a database. Any ideas on how I can achieve this? So far I've tried to check it in the tick function but then it doesn't add the time when the app is in the background.

    import Foundation
    import os.log

/// The class protocol for a Stopwatch instance.
protocol StopwatchDelegate: class {
    func currentTimerUpdated(seconds: String, minutes: String, hours: String)
    func timerHasStarted()
    func timerHasStopped()
    func timerWasReset()
}

/// A container for a stopwatch.
class Stopwatch{

    //var currentTimerSession = [TimerSession] = []

    // *****************************************************************
    // MARK: - Stopwatch Properties
    // *****************************************************************

    /// The middleman for communicating with the view controller.
    weak var delegate: StopwatchDelegate?

    /// The actual Timer for this stopwatch.
    private(set) var timer: Timer?

    /// The time at which the timer was started.
    private(set) var timerStartTime: TimeInterval = 0

    /// The Timer-time at which the last user *pause* occurred.
    private(set) var timerSavedTime: TimeInterval = 0

    private(set) var timerSession = false

    // *****************************************************************
    // MARK: - Stopwatch Class Methods
    // *****************************************************************
    /// Create a new Stopwatch by locating the middleman and starting the timer.
    ///
    /// - Parameter delegate: the middleman to communicate to the view controller.
    /// - Returns: An instance to a ticking `Stopwatch`.
    ///
    init(delegate: StopwatchDelegate) {
        os_log("Initilzing timer.", log: OSLog.default, type: .debug)
        self.delegate = delegate
    }

    // *****************************************************************
    // MARK: - Stopwatch Timer Methods
    // ***************************************************************** *****************************************************************

    /// Start the stopwatch's timer.
    func startTimer() {
        timer = Timer.scheduledTimer(timeInterval: 0.01, target: self,
                                     selector: #selector(timerHasTicked(timer:)),
                                     userInfo: nil, repeats: true)
        RunLoop.current.add(timer!, forMode: RunLoopMode.commonModes)

        /// Record the time at which we started this timer.
        //checkForOngoingTimer()
        timerStartTime = Date.timeIntervalSinceReferenceDate

         timerOriginalStartTime = Date()
         timerSession = true


        delegate?.timerHasStarted()
    }

    /// Pause the Timer
    func stopTimer() {
        /// Save the Time delta of the current Timer.
        let currentTime = Date.timeIntervalSinceReferenceDate
        timerSavedTime += currentTime - timerStartTime
        timer?.invalidate()
        delegate?.timerHasStopped()
    }

    /// Reset the Timer and all of the laps.
    func resetTimer() {
        timerSavedTime = 0
        timerStartTime = 0
        timerSession = false

        timer?.invalidate()
        delegate?.timerWasReset()
    }

    /// Compute the new time values time values:
    ///
    /// - `minutes`: starts at 0 and increments to 59
    /// - `seconds`: starts at 0 and increments to 59
    /// - `hours`: starts at 0 and increments to 59
    ///
    /// - Parameter timer: The instance of the currently *running* Timer.
    ///
    @objc private func timerHasTicked(timer: Timer) {

        /// Find the time delta between start time and now.
        let currentTime = Date.timeIntervalSinceReferenceDate
        let timerElapsedTime: TimeInterval = (currentTime - timerStartTime) + timerSavedTime

        /// Convert elapsed time to minutes, seconds, and hours.
        let minutes = Int(timerElapsedTime) / 60 % 60
        let seconds = Int(timerElapsedTime) % 60
        let hours = Int(timerElapsedTime / 3600)

        let formatter = DateFormatter()
        formatter.timeZone = TimeZone.current
        formatter.dateFormat = "yyyy-MM-dd HH:mm"
        timerOriginalStartTime = formatter.string(from: timerOriginalStartTime)

        /// Let the delegate know the Time has been updated.
        delegate?.currentTimerUpdated(seconds: String(format: "%02u", seconds),
                                      minutes: String(format: "%02u", minutes),
                                      hours: String(format: "%02u", hours))
    }
    }

Upvotes: 0

Views: 944

Answers (1)

Marcel
Marcel

Reputation: 6579

Your timer won't get fired in the background, so the best way to go is is to store the start time when you start the stopwatch, then when the app goes to the background and comes back again, you can calculate the current offset from the starttime.

If you want to support pauzing the timer, you could keep track of start and stop times of the pause and subtract that from the total time.

Upvotes: 2

Related Questions