Аппаратные средства iPhone и пользовательские таймеры со временем рассинхронизируются

#objective-c #ios #nsdate #clock #anti-cheat

#objective-c #iOS #nsdate #часы #античит

Вопрос:

Я пытаюсь определить, продвигает ли пользователь свои часы во время работы приложения. В настоящее время я делаю это, сравнивая, как меняются два таймера: [NSDate timeIntervalSinceReferenceDate] и mach_absolute_time.

Основной алгоритм таков:

  • При запуске приложения сохраните startUserClock (timeIntervalSinceReferenceDate) и startSystemClock (mach_absolute_time, преобразованный в секунды).
  • Периодически сравнивайте текущие значения таймеров с их соответствующими начальными значениями.
  • Если различия отличаются (с некоторой погрешностью), мы должны знать, что таймеры не синхронизированы, что указывает на смену часов — теоретически это возможно только в том случае, если пользователь изменил свои часы.

Однако, похоже, что mach_absolute_time растет немного быстрее, чем timeIntervalSinceReferenceDate . В краткосрочной перспективе это не является серьезной проблемой, но со временем разница увеличивается, и мы начинаем видеть много ложных срабатываний.

Эта проблема, по-видимому, зависит от оборудования. Я вообще не вижу этого на iPad 1, который у меня есть, но коллега видит это на своем iPad 2, и я вижу это в симуляторе.

Я подтвердил, что нет проблем с моим преобразованием mach_absolute_time в секунды, заменив его на CACurrentMediaTime (который использует mach_absolute_time под капотом). Я попытался изменить timeIntervalSinceReferenceDate на другие методы синхронизации (например: CFAbsoluteTimeGetCurrent).

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

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

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

1. не уверен, но меняется ли время на телефоне при смене часовых поясов?

Ответ №1:

Вы можете попробовать использовать gettimeofday, чтобы получить значение текущего системного времени. Это возвращает время с момента начала эпохи.

Ответ №2:

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

Вас интересуют только внезапные изменения в разнице между часами, а не большие отклонения во времени. Итак, вычислите скорость изменения разницы между часами:

 T_Diff := initial difference between clocks
T_Time := time as determined by one clock
Repeat forever:
  T_Diff' := new difference between clocks
  T_Time' := new time as determined by one clock

  # Check if time changed
  if abs((T_Diff'-T_Diff)/(T_Time'-T_Time)) > threshold:
    time_changed()

  # Update state
  T_Diff := T_Diff'
  T_Time := T_Time'

  wait_for_next_update()
  

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

1. К сожалению, эта схема не совсем работает — если пользователь переводит приложение в фоновый режим на длительное время (что очень возможно при многозадачности), при возврате дрейф может быть достаточно большим, чтобы вызвать ложное срабатывание. В нашем случае ложные срабатывания довольно дорогостоящие.

2. Вот почему схема рассматривает дрейф с течением времени, а не сам дрейф. Хотя это не показано выше, вы, вероятно, захотите установить нижний предел времени между обновлениями состояния, чтобы можно было точно вычислить это.