swift 3:手表应用:如果手表进入睡眠状态,界面控制器之间会有延迟

Posted

技术标签:

【中文标题】swift 3:手表应用:如果手表进入睡眠状态,界面控制器之间会有延迟【英文标题】:swift 3: Watch app: if watch goes to sleep there's a delay between interface controllers 【发布时间】:2017-08-03 19:08:25 【问题描述】:

我有一个倒数计时器接口控制器,一旦计时器下降到 00:00,它将启动另一个接口控制器。如果我在计时器到达 00:00 之前保持手表处于活动状态,那么第二个接口控制器将按应有的方式启动。但是,如果手表进入睡眠状态,即使它在计时器到达 00:00 之前处于活动状态,在第二个接口控制器启动之前也会有几秒到一分钟的延迟。

在手表模拟器中运行时不会出现这个缺陷,只是在实际设备上运行时出现。

我正在使用 Xcode 8 和 swift 3。

这是我的第一个接口控制器的代码:

// this func will update the countdown timer
@objc private func updateTimer() 
    totalNumberOfSeconds += 1
    numberOfSeconds += 1
    if (numberOfSeconds == numSecondsInMinute) 
        numberOfSeconds = 0
    

    // only attempt to open the RacingTimer interface if this IC is visible
    if (isStillVisible) 
        // change to the Racing Timer if the countdown timer hits 00:00
        if (totalNumberOfSeconds > originalSecondsTimeInterval) 
            // the watch must have gone to sleep when the countdown timer
            // hit 00:00, so the total num secs is past the orig timer
            // set the numberOfSeconds to total - original to pass to RacingTimer
            numberOfSeconds = totalNumberOfSeconds - originalSecondsTimeInterval

            // launch the racing timer
            WKInterfaceController.reloadRootControllers(withNames: ["RacingTimer"], contexts: [numberOfSeconds])

            // destroy the timer and reset the vars
            countdownClock.invalidate()
            numberOfSeconds = 0
            totalNumberOfSeconds = 0
         else if (totalNumberOfSeconds == originalSecondsTimeInterval) 
            // launch the racing timer
            WKInterfaceController.reloadRootControllers(withNames: ["RacingTimer"], contexts: nil)

            // destroy the timer and reset the vars
            countdownClock.invalidate()
            numberOfSeconds = 0
            totalNumberOfSeconds = 0
        
    



override func awake(withContext context: Any?) 
    super.awake(withContext: context)

    // get race and timer data
    let numSecs = raceDS.timer * 60
    originalSecondsTimeInterval = numSecs
    cdt = NSDate(timeIntervalSinceNow: TimeInterval(numSecs))
    countdownTimer.setDate(cdt as Date)
    countdownClock = Timer.scheduledTimer(timeInterval: 1, target: self,   selector: #selector(updateTimer), userInfo: nil, repeats: true)
    countdownTimer.start()



override func willActivate() 
    // This method is called when watch view controller is about to be visible to user
    super.willActivate()
    nearestMinuteButtonOutlet.setTitle("will activate") // debug only
    didAppear()



// set the visible boolean to true
override func didAppear() 
    super.didAppear()
    isStillVisible = true
    nearestMinuteButtonOutlet.setTitle("did appear")  // debug only



// set the boolean to false
override func didDeactivate() 
    // This method is called when watch view controller is no longer visible
    super.didDeactivate()
    isStillVisible = false
    nearestMinuteButtonOutlet.setTitle("sleeping")  // debug only

我真的不知道为什么手表进入睡眠状态会有延迟。任何帮助将不胜感激。 TIA。

【问题讨论】:

好的,所以我找到了问题所在。不是第二个接口控制器延迟启动,而是当手表进入睡眠状态时,Timer 变量(countdownClock)不会在后台继续处理。它停止。发生这种情况时,不会调用 updateTimer() 函数,因此不会增加 totalNumberOfSeconds 变量等。 手表进入休眠状态时,有没有办法让倒计时时钟在后台运行? 【参考方案1】:

截至watchOS3,没有解决方案让Timer 在后台运行。 Timer 对象也不应用于ios 上的精确时间测量。在iOS 上,您可以选择使用CADisplayLink 来获得准确的计时,但是,这在watchOS3/4 上不可用。

为了在后台测量时间,您应该在应用程序进入后台之前保存当前日期,并计算再次启动应用程序时所经过的时间。

如果您只需要在用户打开您的应用程序时看到另一个InterfaceController,您可以使用使用日期描述的方法,并且您可以在用户打开您的应用程序后立即导航到您的另一个InterfaceController再次应用。

如果你需要在倒计时结束时执行一些代码,你应该安排一个后台任务,它们是目前在watchOS 后台运行代码的唯一方法。

【讨论】:

谢谢大卫。我在其他板上发现了类似的问题并建议了解决方法,所以这就是我要采取的方向。我只需将日期/时间戳保存在 didDeactivate() 中,然后计算 willAppear() 启动后经过的时间,并将经过的时间添加到我的总秒数计数器中。有点难看,但如果这是我需要的,那我就需要这样做。

以上是关于swift 3:手表应用:如果手表进入睡眠状态,界面控制器之间会有延迟的主要内容,如果未能解决你的问题,请参考以下文章

苹果手表处于睡眠模式时如何执行代码

WatchKit 上的延迟警报?

Swift:从手表取消本地通知(安排在手机上)

设备处于睡眠状态时调用 didReceiveApplicationContext?

苹果手表连接手机为啥显示需要更新?

基于ATtiny85轻松制作一款智能手表