【问题标题】:How to properly measure elapsed time in background in Swift如何在 Swift 中正确测量后台经过的时间
【发布时间】:2017-05-20 01:56:11
【问题描述】:

我有这两个功能可以测量手机锁定或应用程序处于后台时的经过时间:

func saveTimeInBackground(){
    startMeasureTime = Int(Date.timeIntervalSinceReferenceDate)
}

func timeOnAppActivated(){
    stopMeasureTime = Int(Date.timeIntervalSinceReferenceDate)
    elapsedTime = stopMeasureTime - startMeasureTime
    seconds = seconds - elapsedTime + 2
    if seconds > 0 {
        timerLbl.text = "time: \(seconds)"
    } else {
        seconds = 0
        timerLbl.text = "time: \(seconds)"
    }
}

然后在 viewDidLoad() 我有观察者在应用程序变为活动/不活动时触发函数:

   NotificationCenter.default.addObserver(self, selector: #selector(saveTimeInBackground), name: Notification.Name.UIApplicationWillResignActive, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(timeOnAppActivated), name: Notification.Name.UIApplicationDidBecomeActive, object: nil)

问题是,当应用程序处于活动状态时,会有 2 秒(大约)的差异,所以我增加了 2 秒,它似乎工作正常,但前提是经过的时间 > 15 秒。 如果我锁定手机并立即将其解锁,则缺少 5 秒或更长时间。例如,如果还剩 50 秒,当我锁定并立即解锁时,还剩 42 秒。

谁能解释一下,我做错了什么?

编辑:应用的逻辑是这样的:

它在 2 名玩家之间开始一场比赛,每场 60 秒。问题是当其中一名玩家锁定手机时,应用程序会停止测量时间。这样如果player1还有10秒可以移动,player2还有50秒。我正在寻找一种可靠的方法来计算时间,即使玩家锁定手机或将应用置于后台。

编辑 2:我想我弄清楚了问题所在:我认为问题与“秒”是 Int 的事实有关,而 Date 不是以及何时转换它被四舍五入了。我没有测试它,但是当我找到解决方案时,我会发布答案。感谢大家的宝贵时间!

【问题讨论】:

  • 不应该只是seconds = elapsedTime + 2吗?
  • seconds = 60, elapsed time = 10, seconds (on active) 60 - 10 (elapsed time),不只是 60 = 10
  • 无论如何,它可以是 seconds -= elapsedTime 或 seconds -= stopMeasureTime - startMeasureTime 但为了清楚起见,我发现这样更好。

标签: swift


【解决方案1】:

您依赖的通知的确切时间不能保证有任何确切的时间。无法保证这些通知中的任何一个确切何时到达,您对此无能为力。正如您所说,即使您的两秒钟修复也是近似的。在不同型号的 iPhone 上,甚至在同一部 iPhone 上的不同时间,它可能会有所不同,具体取决于您检查时 iOS 的繁忙程度。

更重要的是,当您进入后台时,您无法确定自己会留在那里。一旦进入后台,iOS 可能会决定随时终止您的应用。

我不确定这里的目标是什么,但我认为您需要重新考虑您想要做什么,看看是否有其他方法。您当前的两秒破解充其量只会产生一堆其他破解(例如您提到的 15 秒阈值),而不会特别准确。然后,当某些 iOS 更改导致时间更改时,它可能会在下一次 iOS 更新中全部中断。

【讨论】:

  • 感谢您的回答,但只需要取消标记它,因为有计时器应用程序可以执行此操作,测量它们在后台的确切时间。再次感谢您的宝贵时间!
  • 例如,您能否命名一个应用程序,它可以准确地告诉您应用程序从进入后台到进入前台所用的时间?我从来没有听说过。
  • 当然,这个itunes.apple.com/us/app/…使用类似的东西来计算手机被锁定时的经过时间
  • 该应用程序的描述没有提到告诉你屏幕被锁定了多长时间,只是测量了从开始时间到现在的时间。这和你问的不一样。
  • 我可能不够清楚。我要编辑问题。
【解决方案2】:

我会使用 Date 对象来跟踪游戏时间。

func gameStart() {
    gameStartDate = Date()
}

func timeOnAppActivated() {
    let secondsLeft = 60 - abs(gameStartDate?.timeIntervalSinceNow ?? 0)
    if secondsLeft > 0 {
        timerLbl.text = "time: \(secondsLeft)"
    } else {
        timerLbl.text = "time: 0"
    }
}

【讨论】:

    【解决方案3】:

    好的,就像我在问题的编辑 2 中提到的那样: 第一个问题是因为 "seconds" 是一个 Int,然后从 Double 转换它时几乎总是会得到或失去。

    但主要问题是当应用程序进入后台时我必须使计时器无效,而我没有。

    所以现在当应用程序收到将进入后台的通知时使计时器无效,然后在它进入前台时启动它,一切正常。

    【讨论】:

    • 我知道这是一篇旧帖子,但我正在做类似的事情,并认为你可以帮助我。我在应用程序进入后台之前使计时器无效,然后在应用程序返回前台时创建一个新的计时器实例。计时器确实无效,但是当我再次打开应用程序时,新计时器不起作用。更多细节在这里 -> stackoverflow.com/questions/51762833/…
    【解决方案4】:

    为了测试这个正确调用按钮点击这些方法。在后台释放一些资源可能是因为延迟。

    【讨论】:

    • 您好 Jitendra,感谢您抽出宝贵时间,但这并不能回答我的问题。我认为你应该像评论一样发布它。
    • 好的,谢谢你让我知道我应该在哪里评论建议
    猜你喜欢
    • 2014-09-05
    • 1970-01-01
    • 2019-12-30
    • 1970-01-01
    • 2011-11-17
    • 1970-01-01
    相关资源
    最近更新 更多