#ios #swift
Вопрос:
У меня есть проект SwiftUI/SpriteKit.
Я пытаюсь определить время, прошедшее между а) сейчас и б) когда мое приложение было в последний раз активным. Это должно быть чрезвычайно просто, но есть проблема.
У меня есть таймер (используемый для встроенных часов), который вызывает функцию один раз в секунду. В этой функции я сохраняю результат CACurrentMediaTime()
в переменной с именем oldTime
. Это означает, что oldTime
это будет актуально до тех пор, пока приложение находится на переднем плане.
Итак, стратегия заключается в следующем:
- Запишите текущее время, пока приложение активно через
CACurrentMediaTime()
. ЭтоoldTime
. - После перевода приложения в фоновый режим вызовите
.invalidate()
таймер, тем самым гарантируя, что обратный вызов таймера не будет выполняться, пока приложение находится в фоновом режиме. - Сравните
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
.