从Firestore检索数据时,如何防止按钮文本刷新滞后?

时间:2019-04-19 00:34:10

标签: swift firebase timestamp google-cloud-firestore countdown

我将Google Firestore用作我正在制作的iOS应用程序的后端服务器。我正在尝试结合一个倒数计时器来表示游戏何时开始,但是至关重要的是,使用网络时间来反对设备时间,以确保每个人都同时开始游戏。

基本思想是从Firebase检索当前时间戳,从我希望游戏启动时的另一个时间戳值中减去它,然后继续每秒刷新按钮文本(不是标签,因为我需要能够按一下它揭示更多信息)与时差。

当应用启动时,计时器运行得很好,没有/只有很小的延迟,但是,如果我更改了游戏开始时的值,则按钮文本会由于某些原因而出现故障。即使在调试区域,我也看到它滞后。

我已经完成了所有的数学和转换。当前时间戳是一个timeIntervalSince1970值,我将其转换为格式为“ HH:mm:ss”的字符串。我正在从Firebase服务器值中检索此值。我希望游戏开始的另一个时间戳是我存储在Firestore集合中的字符串值。

我将这两个字符串值发送到一个为我找到差异的函数,然后将按钮文本设置为该值。很简单,但我不明白为什么更改第二个时间戳值时它开始滞后。如果我第三次更改它,该应用程序仍会运行,但计时器基本上每8秒左右冻结一次。

覆盖func viewDidAppear(_动画:布尔){

    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语句来计算“ HH:mm:ss”格式。

如果小时> = 10 &&分钟> = 10 &&秒<10 {

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

我希望按钮文本会以正确的倒计时时间刷新。我希望当我更改Firestore时间戳值时,按钮文本会自动刷新并且不会滞后。

实际结果是它滞后了。

1 个答案:

答案 0 :(得分:0)

所以我不确定是否正确,但是我的理解是您要设置一个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,然后按需要格式化差异,而不是格式化每个变量,然后将其比较为字符串