首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Swift中高效且一致的计时(GCD)

Swift中高效且一致的计时(GCD)
EN

Stack Overflow用户
提问于 2018-06-09 22:25:42
回答 1查看 203关注 0票数 0

我正在开发的一个健身应用程序需要每0.1秒将运动数据追加到一个数组中,然而,当应用程序处于后台或设备被锁定时,节能过程意味着这种准确性会漂移至多一秒。

我知道传统的计时器通常遵循概述的行为,因此一直在研究替代方法,特别是GCD计时器。A tutorial written on Medium解释了一个这样的方法,但是,我无法成功地执行这些函数。

我正在运行:

代码语言:javascript
复制
let t = RepeatingTimer(timeInterval: 0.1)
    t.eventHandler = {
        print("Timer Fired")
    }
    t.resume()

在我的viewDidLoad函数中,但是没有用-没有打印任何文本。

代码语言:javascript
复制
override func viewDidLoad() {}

我的完整代码如下:

代码语言:javascript
复制
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的结果。如果找到,则将元素的时间戳(仅)附加到数组(从ab)。

数组c:当函数检查2秒的时间段是否包含1,后跟2(来自数组b)时,将追加数组c的值。这被视为潜在的下降。仅附加时间戳。

然后循环数组c,并在3秒的过程中观察坠落后处于不活动状态的时间段,这表明昏迷和需要发送求救。

我意识到这种方法可能效率低下,也不是最好的方法,然而,对Swift知之甚少,这对我来说似乎是最明显的,如果不考虑背景,这是最有效的。我非常高兴收到关于更合适方法的建议。记录跌倒的动作和方法是based off of this paper.

我的代码原样可以是seen here。对于调试打印的数量,我深表歉意。

EN

回答 1

Stack Overflow用户

发布于 2018-06-10 05:09:50

这是错误的方法。Core Motion为运动处理器提供了一个高效的接口,而您的应用程序不必不断地触发计时器。计时器不会在后台运行,因此这种方法在任何情况下都不会起作用。你在短时间的后台活动中看到了一些漂移,但如果你再多花几分钟,你通常会发现你的应用程序完全停止了生成计时器事件。

如果您想要的是加速计事件,请将CMMotionManager.accelerometerUpdateInterval设置为您想要的(0.1)并调用startAccelerometerUpdates(to:withHandler)来处理这些事件。别忘了在你的应用功能中启用“后台模式:位置更新”。

也就是说,您通常不应该尝试在核心动作层管理健身应用程序。苹果通过HealthKit的HKWorkout提供了更强大和更高水平的支持。诚然,HealthKit有一个令人难以置信的恼人的API,但它将你直接绑定到iOS已经用来跟踪锻炼的系统中,因此你可以免费获得许多功能(特别是帮助解决许多复杂的过滤问题)。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50775270

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档