我正在开发的一个健身应用程序需要每0.1秒将运动数据追加到一个数组中,然而,当应用程序处于后台或设备被锁定时,节能过程意味着这种准确性会漂移至多一秒。
我知道传统的计时器通常遵循概述的行为,因此一直在研究替代方法,特别是GCD计时器。A tutorial written on Medium解释了一个这样的方法,但是,我无法成功地执行这些函数。
我正在运行:
let t = RepeatingTimer(timeInterval: 0.1)
t.eventHandler = {
print("Timer Fired")
}
t.resume()
在我的viewDidLoad函数中,但是没有用-没有打印任何文本。
override func viewDidLoad() {}
我的完整代码如下:
import Foundation
import UIKit
import SystemConfiguration
class accelVController: UIViewController {
override func viewDidLoad() {
let t = RepeatingTimer(timeInterval: 0.1)
t.eventHandler = {
print("Timer Fired")
}
t.resume()
}
}
/// RepeatingTimer mimics the API of DispatchSourceTimer but in a way that prevents
/// crashes that occur from calling resume multiple times on a timer that is
/// already resumed (noted by https://github.com/SiftScience/sift-ios/issues/52
class RepeatingTimer {
let timeInterval: TimeInterval
init(timeInterval: TimeInterval) {
self.timeInterval = timeInterval
}
private lazy var timer: DispatchSourceTimer = {
let t = DispatchSource.makeTimerSource()
t.schedule(deadline: .now() + self.timeInterval, repeating: self.timeInterval)
t.setEventHandler(handler: { [weak self] in
self?.eventHandler?()
})
return t
}()
var eventHandler: (() -> Void)?
private enum State {
case suspended
case resumed
}
private var state: State = .suspended
deinit {
timer.setEventHandler {}
timer.cancel()
/*
If the timer is suspended, calling cancel without resuming
triggers a crash. This is documented here https://forums.developer.apple.com/thread/15902
*/
resume()
eventHandler = nil
}
func resume() {
if state == .resumed {
return
}
state = .resumed
timer.resume()
}
func suspend() {
if state == .suspended {
return
}
state = .suspended
timer.suspend()
}
}
如果有人能对在后台一致执行代码的改进方法提出建议,或者能帮助我实现所包含的代码,我将不胜感激。
更新:这款应用程序本质上是基于跌倒检测的,尽管有与之相关的位置元素。
它基于三个数组。
数组a:包含时间戳,以及加速是否小于最小阈值(1),是否大于最大阈值(2),或者都不大于(0)。它本质上是一个寄存器,2D -[时间戳,状态]
数组b:是遍历数组a并查找状态值1的结果。如果找到,则将元素的时间戳(仅)附加到数组(从a到b)。
数组c:当函数检查2秒的时间段是否包含1,后跟2(来自数组b)时,将追加数组c的值。这被视为潜在的下降。仅附加时间戳。
然后循环数组c,并在3秒的过程中观察坠落后处于不活动状态的时间段,这表明昏迷和需要发送求救。
我意识到这种方法可能效率低下,也不是最好的方法,然而,对Swift知之甚少,这对我来说似乎是最明显的,如果不考虑背景,这是最有效的。我非常高兴收到关于更合适方法的建议。记录跌倒的动作和方法是based off of this paper.
我的代码原样可以是seen here。对于调试打印的数量,我深表歉意。
发布于 2018-06-10 05:09:50
这是错误的方法。Core Motion为运动处理器提供了一个高效的接口,而您的应用程序不必不断地触发计时器。计时器不会在后台运行,因此这种方法在任何情况下都不会起作用。你在短时间的后台活动中看到了一些漂移,但如果你再多花几分钟,你通常会发现你的应用程序完全停止了生成计时器事件。
如果您想要的是加速计事件,请将CMMotionManager.accelerometerUpdateInterval
设置为您想要的(0.1)并调用startAccelerometerUpdates(to:withHandler)
来处理这些事件。别忘了在你的应用功能中启用“后台模式:位置更新”。
也就是说,您通常不应该尝试在核心动作层管理健身应用程序。苹果通过HealthKit的HKWorkout
提供了更强大和更高水平的支持。诚然,HealthKit有一个令人难以置信的恼人的API,但它将你直接绑定到iOS已经用来跟踪锻炼的系统中,因此你可以免费获得许多功能(特别是帮助解决许多复杂的过滤问题)。
https://stackoverflow.com/questions/50775270
复制相似问题