Как предотвратить задержку обновления текста кнопки при получении данных из Firestore? - PullRequest
0 голосов
/ 19 апреля 2019

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

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

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

Я сделал всю математику и преобразования.Текущая отметка времени представляет собой значение timeIntervalSince1970, которое я преобразовал в строку с форматом «ЧЧ: мм: сс».Я получаю это значение из значения сервера Firebase.Другая временная метка, в которой, когда я хочу запустить игру, - это строковое значение, которое я сохранил в коллекции в Firestore.

Я отправляю эти два строковых значения в функцию, которая находит для меня разницу, и я устанавливаютекст кнопки к значению.Это просто, но я не могу понять, почему он начинает лагать, когда я изменяю значение второй метки времени.Если я изменю это в третий раз, приложение все еще работает, но таймер в основном останавливается каждые 8 ​​секунд или около того.

переопределить func viewDidAppear (_ animated: Bool) {

    DispatchQueue.main.async {

    let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in

            Firestore.firestore().collection("countdown").document("thursday")
                .addSnapshotListener { documentSnapshot, error in
                    guard let document = documentSnapshot else {
                        print("Error fetching document: \(error!)")
                        return
                    }
                    guard let theTime = document.data() else {
                        print("Document data was empty.")

                        return
                    }
                    print("Current data: \(theTime)")

            let stringData = "\(theTime)"
            let finalTime = stringData.substring(from: 9, to: 16) 

// Возможно, не самый обычный способ получить правильный формат, но он работает для меня.Конечно, я открыт для предложений.

            var currentTimeStamp: Double?

            let ref = Database.database().reference().child("serverTimestamp")

            ref.setValue(ServerValue.timestamp())

            ref.observe(.value, with: { snap in
                if let t = snap.value as? Double {

                    currentTimeStamp = t/1000

                    let unixTimestamp = currentTimeStamp
                    let date = Date(timeIntervalSince1970: unixTimestamp!)
                    let dateFormatter = DateFormatter()
                    dateFormatter.timeZone = TimeZone(abbreviation: "EDT") //Set timezone that you want
                    dateFormatter.locale = NSLocale.current
                    dateFormatter.dateFormat = "HH:mm:ss" //Specify your format that you
                    let strDate = dateFormatter.string(from: date)

                    let dateDiff = self.findDateDiff(time1Str: strDate, time2Str: finalTime)
                    print("This is the countdown time: \(dateDiff)")

                }
            })
        }
    }
    }

// Это всего лишь пик в функции, которая выполняет всю математику и выводит время обратного отсчета в тексте кнопки.У меня есть много операторов if для всех сценариев времени для математического формата «ЧЧ: мм: сс».

если часы> = 10 && минут> = 10 && секунд <10 {</p>

        self.time.setTitle(("\(Int(hours)):\(Int(minutes)):0\(Int(seconds))"), for: .normal)

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

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

1 Ответ

0 голосов
/ 19 апреля 2019

Так что я не уверен, правильно ли я понял, но, насколько я понимаю, вы устанавливаете объект Timer для запуска вызова .observe каждую секунду? Если это так, ваши вызовы Firebase не извлекают данные вовремя (.observe является асинхронным, поэтому отсюда и возникает задержка).

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

Когда каждому устройству нужна кнопка обратного отсчета, они извлекают метку времени, а затем запускают объект Timer с интервалом в 1 секунду, чтобы извлечь текущее время из чего-то вроде NSDate (). TimeIntervalFrom1970, найдите разницу между ними, затем установите текст кнопки (и отключите Timer, как только обратный отсчет закончится). Может как то так?

override func viewDidAppear(_ animated: Bool) {

    // get time to count down from
    Firestore.firestore().collection("countdown").document("thursday").getDocument { (document, error) in

        guard let document = document, document.exists else {
            // document doesn't exist
            return
        }

        guard let theTime = document.data() else {
            print("Document data was empty.")
            return
        }

        print("Current data: \(theTime)")

        let stringData = "\(theTime)"
        let finalTime = stringData.substring(from: 9, to: 16)
        self.setTimer(for: finalTime)
    }
}

// set Timer

func setTimer(for finalTime: String) {

    let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in

        let timeNow = Date()

        let dateFormatter = DateFormatter()
        dateFormatter.timeZone = TimeZone(abbreviation: "EDT")
        dateFormatter.locale = NSLocale.current
        dateFormatter.dateFormat = "HH:mm:ss"

        let strDate = dateFormatter.string(from: timeNow)

        // stop timer once finalTime reached. Idk what finalDate is but here's if it's formatted the same as strDate is.
        guard finalTime != strDate else {
            timer.invalidate()
            print("countdown over")

            return
        }

        let dateDiff = self.findDateDiff(time1Str: strDate, time2Str: finalTime)

        print("This is the countdown time: \(dateDiff)")
    }

    timer.fire()
}

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

...