如何从 WatchKit 正确获取心率?

Posted

技术标签:

【中文标题】如何从 WatchKit 正确获取心率?【英文标题】:How to properly get heart rate from WatchKit? 【发布时间】:2016-02-23 22:54:25 【问题描述】:

我试图简单地显示 Apple Watch 上次记录的心率。下面是我正在尝试的,但 updateHeartRate 的完成处理程序中的 results 变量会获取数百万条记录并杀死应用程序(几乎看起来像损坏的数据或做错了什么):

class InterfaceController: WKInterfaceController 

    @IBOutlet var heartLabel: WKInterfaceLabel!

    let heartRateUnit = HKUnit.countUnit().unitDividedByUnit(HKUnit.minuteUnit())
    let heartRateQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)

    override func awakeWithContext(context: AnyObject?) 
        super.awakeWithContext(context)
    

    override func willActivate() 
        super.willActivate()

        guard HKHealthStore.isHealthDataAvailable() else 
            heartLabel.setText("Not available")
            return
        

        requestHealthKitAuthorization()
        queryHeartRateSample()
    

    @IBAction func workoutMenuTapped() 

    


private extension InterfaceController 

    func requestHealthKitAuthorization() 
        guard let heartRateQuantityType = heartRateQuantityType else 
            displayNotAllowed()
            return
        

        let dataTypes = Set(arrayLiteral: heartRateQuantityType)

        HKHealthStore.sharedInstance?.requestAuthorizationToShareTypes(nil, readTypes: dataTypes) 
            [unowned self] success, error in

            guard success else 
                self.displayNotAllowed()
                return
            

            self.queryHeartRateSample()
        
    

    func displayNotAllowed() 
        heartLabel.setText("Not allowed")
    

    func queryHeartRateSample() 
        guard let heartRateQuery = getHeartRateQuery() else  return 
        HKHealthStore.sharedInstance?.executeQuery(heartRateQuery)
    

    func updateHeartRate(samples: [HKSample]?) 
        guard let heartRateSamples = samples as? [HKQuantitySample] else  return 

        dispatch_async(dispatch_get_main_queue()) 
            guard let sample = heartRateSamples.first else  return 
            let value = sample.quantity.doubleValueForUnit(self.heartRateUnit)
            self.heartLabel.setText(String(UInt16(value)))
        
    

    func getHeartRateQuery() -> HKQuery? 
        guard let heartRateQuantityType = heartRateQuantityType else 
            displayNotAllowed()
            return nil
        

        let heartRateQuery = HKSampleQuery(sampleType: heartRateQuantityType,
            predicate: nil,
            limit: 100,
            sortDescriptors: nil) 
                [unowned self] query, results, error in
                guard let results = results as? [HKQuantitySample] else  return 
                self.updateHeartRate(results)
        

        return heartRateQuery
    



@available(ios 8.0, *)
public extension HKHealthStore 

    class var sharedInstance: HKHealthStore? 
        if !HKHealthStore.isHealthDataAvailable() 
            return nil
        

        struct Singleton 
            static let instance = HKHealthStore()
        

        return Singleton.instance
    


它确实要求我授予权限,但仍然不会触发更新。我是不是做错了什么?

【问题讨论】:

【参考方案1】:

我更喜欢使用HKAnchoredObjectQuery只搜索添加到HealthKit的新数据,这样可以避免查询所有数据,因此您可以通过以下方式获取最新的心率值权限:

private let healthStore = HKHealthStore()

private let heartRateType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
private let heartRateUnit = HKUnit(fromString: "count/min")

/**
 Start to measure the heart rate.
 */
func startToMeasure() 
    self.healthStore.executeQuery(self.createStreamingQuery()!)



/**
Create a query to receive new heart rate data from the HealthKit store.

- returns: The created query
*/
private func createStreamingQuery() -> HKQuery 
    let predicate = HKQuery.predicateForSamplesWithStartDate(NSDate(), endDate: nil, options: .None)

    let query = HKAnchoredObjectQuery(type: heartRateType, predicate: predicate, anchor: nil, limit: Int(HKObjectQueryNoLimit)) 
        (query, samples, deletedObjects, anchor, error) -> Void in
        self.formatSamples(samples)
    

    query.updateHandler =  (query, samples, deletedObjects, anchor, error) -> Void in
        self.formatSamples(samples)
    

    return query


/**
 Format the samples received from HealthKit.

 - parameter samples: Some samples
 */
private func formatSamples(samples: [HKSample]?) 
    guard let samples = samples as? [HKQuantitySample] else  return 
    guard let quantity = samples.last?.quantity else  return 

    let value = Int(quantity.doubleValueForUnit(heartRateUnit))
    print("HeartRate: \(value)") 

上面的代码需要集成到某个类或者UIViewController你有。我在上面的代码中使用了一个谓词来按日期过滤,如果不相关,您可以将其删除。

希望对你有所帮助。

【讨论】:

在模拟器中运行此代码并获取心率?

以上是关于如何从 WatchKit 正确获取心率?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 iPhone 无法从 Apple Watch 获取心率数据,但手表扩展程序却可以?

为啥我的 iPhone 无法从 Apple Watch 获取心率数据,但手表扩展程序却可以?

如何从 Apple Watch 获取传感器数据到 iPhone?

Apple Watch、WatchKit 和 NSUserDefaults [重复]

WatchKit 中的本地通知

来自 Apple Watch 的 iOS 实时心率统计数据