Таймер. Хочу знать все!)


#1

Вчера я создал таймер и установил время по типу:
3 дня - 24 часа - 60 мин - 59 сек
Запустил таймер и время пошло обратным отчетом.
Закрыл таймер.
Открыл таймер сегодня и время начало идти с того момента когда было закрыто приложение.
Как сделать так, чтобы при открытии приложения отчет времени начинался с реально прошедшего времени? Ну, типа таймер при закрытии приложения не останавливался)


#2

Время само по себе не останавливается, зачем какой то таймер бекграунде ещё крутить? Проще запомнить дату начало отсчета и потом вычитать её из текущей, тем самым получая реально прошедшее время с начала отсчета.


#3

Как сделать что бы при выходе или при закрытии приложения сохранялась текущая дата, а при открытии приложения, от текущей даты отнять сохраненную дату? Что бы по итогу получить разницу в годах, месяцах, днях, час, минутах, секундах - все Int.


#4

User Defaults для сохранения


#5

Сохранить как и сказали в UserDefaults, а разницу календарь знает:

let start = Date()
let end = start.addingTimeInterval(5 * 24 * 60 * 60)

let components = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: start, to: end)

print("""
    year: \(components.year!)
    month: \(components.month!)
    day: \(components.day!)
    hour: \(components.hour!)
    minute: \(components.minute!)
    second: \(components.second!)
""")


#6

Что то начинаю подтупливать))

У меня есть переменные:

var timer = Timer()
private var year1000 = 1000
private var year1 = 100
private var month1 = 12
private var days1 = 30
private var hour1 = 24
private var min1 = 60
private var sec1 = 59

и есть метод который вставляет туда значения

@objc func CLOCK() {
        if SECONDS >= 1 {
            SECONDS = SECONDS - 1
            secondsLabel.text = String("\(SECONDS) секунд")
        }
        if sec1 >= 0 {
            sec1 = sec1 - 1
            secLabel.text = String("\(sec1)")
            minLabel.text = String("\(min1)")
            hourLabel.text = String("\(hour1)")
            dayssLabel.text = String("\(days1)")
            monthhLabel.text = String("\(month1)")
            yearssLabel.text = String("\(year1000)\(YEARS)")
        }
        if sec1 == 0 {
            min1 = min1 - 1
            sec1 = 60
        }
        if min1 == 0 {
            hour1 = hour1 - 1
            min1 = 60
        }
        if hour1 == 0 {
            days1 = days1 - 1
            hour1 = 24
        }
        if days1 == 0 {
            month1 = month1 - 1
            days1 = 30
        }
        if month1 == 0 {
            year1 = year1 - 1
            month1 = 30
        }
    }
// запускаю таймер
if YEARS == result {
            timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.CLOCK), userInfo: nil, repeats: true)
           }

после этого label отображают эти данные таймера с обратным отсчетом :

year1000 = 1000
year1 = 100
month1 = 12
days1 = 30
hour1 = 24
min1 = 60
sec1 = 59

теперь когда пользователь закрывает приложение надо что бы эти данные сохранились (не понимаю этот момент)
и потом когда открываем приложение получаем разницу (не понимаю этот момент)

let start = Date()
let end = start.addingTimeInterval(5 * 24 * 60 * 60)
let components = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: start, to: end)
вычитаем ее от сюда
   year1000 = 1000
    year1 = 100
    month1 = 12
    days1 = 30
    hour1 = 24
    min1 = 60
    sec1 = 59

?

#7

Я точно не знаю, как делают правильно, но за сегодня я понял так (на примере прогрузки вью контроллера):

var timer = Timer()
let year1000: Int = 1000
let year1 = 100
let month1 = 12
let days1 = 30
let hour1 = 24
let min1 = 3
let sec1 = 59
var futureDate: Date!

override func viewDidLoad() {
    super.viewDidLoad()
    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .full
    dateFormatter.timeStyle = .full
    
    if let dateString = UserDefaults.standard.string(forKey: "futureDate"), let date = dateFormatter.date(from: dateString) {
        futureDate = date
    } else {
        futureDate = Calendar.current.date(byAdding: .init(era: year1000, year: year1, month: month1, day: days1, hour: hour1, minute: min1, second: sec1), to: Date())
        let futureDateString = dateFormatter.string(from: futureDate)
        UserDefaults.standard.set(futureDateString, forKey: "futureDate")
    }
    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateLabels), userInfo: nil, repeats: true)
    timer.fire()
}

@objc func updateLabels () {
    let components = Calendar.current.dateComponents([.era,.year,.month,.day,.hour,.minute,.second], from: Date(), to: futureDate)
    era.text = components.era?.description
    year.text = components.year?.description
    month.text = components.month?.description
    day.text = components.day?.description
    hour.text = components.hour?.description
    minute.text = components.minute?.description
    second.text = components.second?.description
    
    if components.minute == 57 { // любая другая логика
        timer.invalidate()
        UserDefaults.standard.removeObject(forKey: "futureDate")
    }
}

Если делают не так, или вы наблюдаете печальную практику в коде выше, пожалуйста, укажите на это. Мне бы было очень полезно знать.