Время, прошедшее с момента активации приложения, неверно

#ios #swift

Вопрос:

У меня есть проект SwiftUI/SpriteKit.

Я пытаюсь определить время, прошедшее между а) сейчас и б) когда мое приложение было в последний раз активным. Это должно быть чрезвычайно просто, но есть проблема.

У меня есть таймер (используемый для встроенных часов), который вызывает функцию один раз в секунду. В этой функции я сохраняю результат CACurrentMediaTime() в переменной с именем oldTime . Это означает, что oldTime это будет актуально до тех пор, пока приложение находится на переднем плане.

Итак, стратегия заключается в следующем:

  1. Запишите текущее время, пока приложение активно через CACurrentMediaTime() . Это oldTime .
  2. После перевода приложения в фоновый режим вызовите .invalidate() таймер, тем самым гарантируя, что обратный вызов таймера не будет выполняться, пока приложение находится в фоновом режиме.
  3. Сравните oldTime с CACurrentMediaTime() тем, когда приложение возвращается из фонового режима. CACurrentMediaTime() - oldTime следует дать время, прошедшее.

Эта стратегия отлично работает при тестировании на устройстве с помощью Xcode. Однако при тестировании с помощью тестового полета время, прошедшее, намного меньше. Если я переведу приложение в фоновый режим, а затем вернусь через 10 минут, то прошедшее время может составить около 1 минуты. Таким образом, он действительно регистрирует некоторое время, которое проходит, что любопытно.

В SceneDelegate , у меня есть следующий код, который делает недействительным и перезапускает таймер в зависимости от состояния:

 func sceneWillResignActive(_ scene: UIScene) {
     //The app is being interrupted. Invalidate the timer so it doesn't run in the background and screw up the time elapsed.
     MainData.appWideTimer?.invalidate()
     MainData.appWideTimer = nil
}

func sceneDidBecomeActive(_ scene: UIScene) {
     //The app is active again. Start the timer.
     mainData.startTheTimer() //Sets a timer via Timer.scheduledTimer()
}
 

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

 @objc func updateClock() {
     let now = CACurrentMediaTime()
     let timeSinceAppWasActive: Double = now - oldTime

     //timeSinceAppWasActive will be incorrect when tested via TestFlight

     oldTime = now
}
 

У меня совсем нет идей, так что любая помощь будет очень признательна!

Спасибо!

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

1. где хранится старое время?

Ответ №1:

Вы не должны использовать CACurrentMediaTime . Я полагаю, что это основано на времени с момента последнего запуска устройства, игнорируя время, когда оно спит. (В документах говорится , что это основано на mach_absolute_time , а в документах mach_absolute_time говорится, что значение «начинается[с] в произвольной точке» и что «эти часы не увеличиваются, пока система спит».)

CAMediaTime предназначен для использования в основной анимации и временных анимационных последовательностях. Он дает значения, которые увеличиваются, начиная «с произвольной точки» и непрерывно запускаются во время анимации, но нет никакой гарантии, что он будет работать непрерывно, пока ваше приложение находится в фоновом режиме.

Вы должны использовать результат вызова Date() . Это дает вам время, которое всегда должно быть правильным (при условии, что часы устройства точны).

Разница между 2 значениями даты-это количество секунд (включая доли секунды с точностью до миллисекунды), прошедших между вызовами Date() функции, и они должны быть правильными, несмотря на спящий режим или перезапуск устройства.

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

1. Вау, я совершенно неправильно понял цель CACurrentMediaTime() . Спасибо вам за вашу помощь!

Ответ №2:

Вы не можете использовать таймер для такого рода вещей, потому что таймеры не работают в фоновом режиме. И тебе это не нужно. И использование CACurrentMediaTime полностью выходит за рамки нормы.

Чтобы узнать, когда приложение стало неактивным, просто посмотрите на часы и запишите время (а именно Date() ), когда приложение становится неактивным. Когда вы захотите узнать, сколько времени прошло с тех пор, просто снова посмотрите на часы и вычтите.

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

1. 1) Мне не нужен или я не хочу запускать таймер в фоновом режиме; я не поэтому использую таймер. 2) В чем дело CACurrentMediaTime() ? Почему это может привести к неправильному значению? 3) Таймер на самом деле не проблема, поскольку это просто удобный способ записи текущего времени, поскольку таймер уже требуется для другой функции (часы в приложении). 4) Я попробую использовать Date() вместо этого, и я попытаюсь просто записать значение при входе в фоновый режим вместо того, чтобы постоянно обновлять его updateClock .