(Swift) Какая реализация API используется для фоновых таймеров? - PullRequest
0 голосов
/ 24 апреля 2018

Рассмотрим такое приложение, как Clash Royale (и многие другие), в котором есть таймер обратного отсчета наград, который генерирует вознаграждения или другую игровую валюту так часто, как это делается?

Мой текущий процесс состоит в том, чтобы получить текущую дату и время из Google и загрузить их в данные пользователя в Firebase, когда приложение переходит в любой фоновый режим (или завершается), а затем при повторном запуске приложения оно читает текущая дата и время снова и сравнивает их со старым значением в Firebase ... Затем я делаю некоторые математические расчеты, чтобы выяснить, какой должен быть таймер И сколько валюты было заработано за истекшее время ... Но это кажется СУПЕР гулким .

Есть ли что-то еще, что может справиться с таким фоновым обратным отсчетом?

Большое спасибо!

Ответы [ 4 ]

0 голосов
/ 24 апреля 2018

Сначала я не осознавал, что вы имеете в виду настоящий фон (например, когда приложение работает в фоновом режиме), поэтому мой другой ответ не сработает.Для того, что вы хотите сделать, это правильный вариант использования для запланированного уведомления.

Начиная с iOS 10, вы можете запланировать локальное уведомление с помощью пользовательских триггеров.Одним из таких триггеров является временной интервал.Вы бы сделали что-то вроде этого:

func scheduleNotificationAfter(numberOfSeconds: Double) {
    let content = UNMutableNotificationContent()
    content.title = "Time's up!"

    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: numberOfSeconds, repeats: false)

    let notification = UNNotificationRequest(identifier: "Times Up Notification", content: content, trigger: trigger)

    UNUserNotificationCenter.current().add(notification, withCompletionHandler: nil)
}
0 голосов
/ 24 апреля 2018

Я согласен с Мохитом.Я не вижу серьезных проблем с вашим дизайном.Есть способы победить это, взломав программу напрямую, но это верно для любого решения.Ваша проста, элегантна и эффективна против большинства простых атак (противостоять сложным атакам на намного сложнее и, возможно, не стоит).Это был бы мой первый выбор.

Я бы порекомендовал закрепить сертификат.В противном случае, ваша программа может легко обмануть неправильное чтение сервера времени.Прикрепление сертификата говорит вашему приложению, что нужно доверять только определенному сертификату HTTPS или группе сертификатов, а не только каждому сертификату, которому доверяет устройство.Для ознакомления см. Закрепление сертификата .Чтобы упростить реализацию ObjC, см. CertificateValidator .

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

Если желателен автономный доступ, вы можете воспользоваться инструментом mach_absolute_time.Это сложнее в использовании, и его сложнее защитить, чем ваш подход, но он может работать в автономном режиме.mach_absolute_time возвращает монотонно увеличивающиеся часы.То есть он всегда идет с постоянной скоростью, даже если пользователь изменяет системные часы.Это не в секундах, однако.Вам нужно использовать AbsoluteToDuration для конвертации.(Подробнее см. QA1398 .) Сбрасывается при перезагрузке устройства.В принципе, вы можете сравнить время, которое оно предоставляет, со временем, которое системные часы предоставляют, чтобы определить, являются ли системные часы надежными, и если это так, вы можете начислять очки в автономном режиме.Стоит ли это дополнительной работы (и может ли она иметь ложные негативы), зависит от вашего варианта использования.

0 голосов
/ 24 апреля 2018

Библиотека Foundation содержит класс Timer, с которым вы можете ознакомиться с документацией для здесь .

. Он предоставляет API для увольнения по истечении определенного времени.Метод конструктора, который вы хотите использовать:

class func scheduledTimer(withTimeInterval: TimeInterval, repeats: Bool, block: (Timer) -> Void) -> Timer

(потому что другая версия использует селекторы, и кто хочет писать kludgy Objective-C, когда они пишут Swift, если они могутизбежать этого?)

Итак, например, допустим, у вас есть

  1. метка secondsLeftLabel, которая показывает оставшиеся секунды
  2. функция timesUp()Вы хотите вызвать, как только он завершится

Сначала вам нужно будет создать свойство таймера и свойство secondsLeftInTimer:

private var timer: Timer?
private var secondsLeftInTimer: Double = 0

Затем вы можете реализовать такую ​​функцию:

func setUpTimer(numberOfSeconds: Double) {
    secondsLeftInTimer = numberOfSeconds
    timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] (_) in
        self?.secondElapsed()
    }
}

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

func secondElapsed() {
    secondsLeftInTimer -= 1
    secondsLeftLabel.text = "\(secondsLeftInTimer) seconds left"

    if secondsLeftInTimer <= 0 {
        timer.invalidate()
        timer = nil
        timesUp()
    }
}

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

func setUpTimer(numberOfSeconds: Int) {
    secondsLeftInTimer = Double(exactly: numberOfSeconds)
0 голосов
/ 24 апреля 2018

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

...