根据Apple文档,可以使用WKInterfaceTimer(Watch本地,倒计时但结束时不触发任何事件)和NSTimer(在计时器结束时触发方法)。所以,我的App Interface Controller中有一个NSTimer和一个WKInterfaceTimer。在模拟器上,在WatchApp运行时的所有方案中,NSTimer&当Watch处于唤醒或睡眠模式时(按照Apple手册中的说明使用模拟器锁定/解锁),WKInterfaceTimer会继续倒计时(正如他们所应)。
然而,在真实的物理观察中,2个定时器在Watch显示器睡眠(中断)和唤醒状态下表现不同。睡眠模式PAUSES接口控制器的NSTimer,但WKInterfaceTimer保持倒计时(应该如此)。
因此,2个定时器在第一次Apple Watch睡眠时立即失去同步(NSTimer暂停,WKInterfaceTimer一直在倒计时)。寻求其他人的经验以及是否有人采用了一种很好的方法来保持NSTimer和WKInterfaceTime同步,无论Watch模式如何(睡眠或清醒)。
答案 0 :(得分:3)
似乎您可以存储倒计时的结束时间(例如,在NSUserDefaults
中),然后在willActivate
上,重新设置您的NSTimer,以便在正确的时间完成。或者,您可以调用您的iPhone应用程序来安排本地通知,但无法保证通知会传递给您的手表,因此这可能不适合您。
答案 1 :(得分:1)
我的研究结论是,根据当前发布的WatchKit的Apple文档,您需要2个计时器:Apple Watch上的WK计时器和iPhone上的NSTimer。 2个定时器应同时启动/触发,WK定时器在两个唤醒/睡眠模式下继续倒计时,NSTimer作业将在定时器结束时发出警报/发送通知。
要使两个计时器保持同步,您需要在用户启动Apple Watch WK计时器时立即触发iPhone NSTimer。
答案 2 :(得分:0)
在willActivate / didDeactivate中启动/停止WKInterfaceTimer:
class MyAwesomeInterfaceController: WKInterfaceController {
@IBOutlet var timer: WKInterfaceTimer!
override func willActivate() {
super.willActivate()
timer.start()
}
override func didDeactivate() {
super.didDeactivate()
timer.stop()
}
}
答案 3 :(得分:0)
当Apple Watch屏幕变为空白时,它会让应用程序进入睡眠状态并暂停您已启动的Timer
(s),直到应用程序返回到前台。
这在模拟器中不会发生,但会导致真实设备出现问题
但是,WKInterfaceTimer
不受影响,因为它基于未来日期并在内部处理。
因此,只需比较Timer
块中的2个日期并观察这两个日期之间的差异,即可在应用程序返回前景后保持计时器同步。
在下面的示例中,如果您只想更新计时器并知道倒计时何时完成,那么以下内容就足够了:
//Globally declared
@IBOutlet var interfaceTimerCountDown: WKInterfaceTimer!
var countdownToDate: Date?
func startCountdown(from count: TimeInterval) {
//Create a future date to which the countdown will count to
countdownToDate = Date().addingTimeInterval(count)
//Set and Start the WKInterfaceTimer
interfaceTimerCountDown.setDate(countdownToDate!)
interfaceTimerCountDown.start()
//Start your own Timer
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] (timer) in
//Get current date
let currentDate = Date()
//Get difference between future date and current date
let dxTimeInSeconds = self?.countdownToDate!.timeIntervalSince(currentDate) ?? 0
print(dxTimeInSeconds)
//Check if countdown has completed
if dxTimeInSeconds <= 0 {
//...do something
print("Countdown complete!")
timer.invalidate()
}
}
}
WKInterfaceTimer
和Timer
将在几毫秒内不同步,因此如果您想要在WKInterfaceTimer
的同时>强制更新用户界面计数已更新,那么上述逻辑是不够的
在我的情况下,我想更新图像;像一个环形动画&amp;解决这个问题的唯一方法是将WKInterfaceTimer
转储为WKInterfaceLabel
+一个WKInterfaceGroup
,然后在计时器块中手动更新标签和组的背景图像。
//Declared globally
//for image; to simulate a ring animation image
@IBOutlet var group_lblTimerCount: WKInterfaceGroup!
//Simple label inside a WKInterfaceGroup
@IBOutlet var lblTimerCount: WKInterfaceLabel! //inside group_lblTimerCount
var countdownToDate: Date?
func startCountdown(from count: Int) {
//Create a future date to which the countdown will count to
countdownToDate = Date().addingTimeInterval(TimeInterval(count))
//Update Label and UI
updateTimerLabel(to: count,
from: count)
//Start your own Timer
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] (timer) in
//Get current date
let currentDate = Date()
//Get difference between future date and current date
let dxTimeInSeconds = self?.countdownToDate!.timeIntervalSince(currentDate) ?? 0
//Update Label and UI
let dxTimeInSeconds_Int = Int(round(dxTimeInSeconds))
self?.updateTimerLabel(to: dxTimeInSeconds_Int,
from: count)
//Check if countdown has completed
if dxTimeInSeconds <= 0 {
//...do something
print("Countdown complete!")
//Stop timer
timer.invalidate()
}
}
}
func updateTimerLabel(to count: Int, from total: Int) {
lblTimerCount.setText("\(count)")
updateTimerRing(to: count,
from: total)
}
func updateTimerRing(to count: Int, from total: Int) {
/*
I have 60 images for the ring named from "ring60" to "ring0"
Generated at: http://hmaidasani.github.io/RadialChartImageGenerator
*/
let numberOfImages = 60 //The total number of images you have
let imageIndex = "\(Int(count * numberOfImages/total))"
let imageName = "ring\(imageIndex)"
group_lblTimerCount.setBackgroundImageNamed(imageName)
}
PS:我试图找到一个优雅的解决方案来解决所有这一问题,但实际上并没有找到一个现成的例子,所以我正在分享我最终的结果。
希望它有助于某人 :)