从 HealthKit 查询心率值会使应用程序崩溃

Querying Heart Rate value from HealthKit crashes app

我试图在每次按下按钮时将我的心率显示为标签。我希望能够在打印心率时也选择一个特定的日期我希望能够通过电子邮件发送这个特定的心率。但我的主要问题是,每当我单击我的按钮时,我都会不断 "Thread 1: signal SIGABRT"。一切似乎都按预期链接。

import UIKit
import HealthKit

class ViewController: UIViewController {
let healthStore = HKHealthStore()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

@IBAction func authoriseHealthKitAccess(_ sender: Any) {
    let healthKitTypes: Set = [

        HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
    ]
    healthStore.requestAuthorization(toShare: healthKitTypes, read: healthKitTypes) { (_, _) in
        print("Authorising")
    }
    healthStore.requestAuthorization(toShare: healthKitTypes, read: healthKitTypes) { (bool, error) in
        if let e = error {
            print("oops something went wrong during authorisation \(e.localizedDescription)")
        } else {
            print("User has completed the authorization process")
        }
    }
}

func getTodaysHeartRate(completion: @escaping (Double) -> Void) {

    let heartRateType = HKQuantityType.quantityType(forIdentifier: .heartRate)!

    let now = Date()
    let startOfDay = Calendar.current.startOfDay(for: now)
    let predicate = HKQuery.predicateForSamples(withStart: startOfDay, end: now, options: .strictStartDate)

    let query = HKStatisticsQuery(quantityType: heartRateType, quantitySamplePredicate: predicate, options: .cumulativeSum) { (_, result, error) in
        var resultCount = 0
        guard let result = result else {
            print("Failed to fetch heart rate")
            completion(Double(resultCount))
            return
        }
        if let sum = result.sumQuantity() {
            resultCount = Int(sum.doubleValue(for: HKUnit.count()))
        }

        DispatchQueue.main.async {
            completion(Double(resultCount))
        }
    }
    healthStore.execute(query)
}

@IBOutlet weak var heartRate: UILabel!
@IBAction func getHeartRate(_ sender: Any) {
    getTodaysHeartRate { (result) in
        print("\(result)")
        DispatchQueue.main.async {
            self.heartRate.text = "\(result)"
        }
}
}

}

Crash Console: 2019-02-22 14:29:28.314380-0400 HeartRateSample[16416:2767191] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Statistics option HKStatisticsOptionCumulativeSum is not compatible with discrete data type HKQuantityTypeIdentifierHeartRate' * First throw call stack: (0x213d51ea4 0x212f21a50 0x213c58484 0x2265cf760 0x226575d60 0x22657e298 0x1035e4dc8 0x1035f382c 0x22657dcb0 0x226534bd4 0x102749ebc 0x10274a8dc 0x10274ae3c 0x24103e314 0x240acbd54 0x240acc074 0x240acb074 0x241077a6c 0x241078cd0 0x241057fcc 0x241126e38 0x241129830 0x241122320 0x213ce20e0 0x213ce2060 0x213ce1944 0x213cdc810 0x213cdc0e0 0x215f55584 0x24103cc00 0x10274d138 0x21379abb4) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)

你走在正确的轨道上。你得到的错误很简单。心率是一个离散选项,与统计选项 Cumulative Sum 不兼容。

来自文档:

You cannot combine a discrete option with a cumulative option.

Click here to learn more about HKStatisticsOptions

解法:

您需要使用 .discreteMostRecent 而不是 .cumulativeSum

更新代码以适应必要的更改:

@available(iOS 12.0, *)
    func getTodaysHeartRate(completion: @escaping (Double) -> Void) {
        let heartRateType = HKQuantityType.quantityType(forIdentifier: .heartRate)!
        let now = Date()
        let startOfDay = Calendar.current.startOfDay(for: now)
        let predicate = HKQuery.predicateForSamples(withStart: startOfDay, end: now, options: .strictStartDate)

    // replaced options parameter .cumulativeSum with .discreteMostRecent
    let query = HKStatisticsQuery(quantityType: heartRateType, quantitySamplePredicate: predicate, options: .discreteMostRecent) { (_, result, error) in
        var resultCount = 0
        guard let result = result else {
            print("Failed to fetch heart rate")
            completion(Double(resultCount))
            return
        }

        // More changes here in order to get bpm value
        guard let beatsPerMinute: Double = result.mostRecentQuantity()?.doubleValue(for: HKUnit.count().unitDivided(by: HKUnit.minute())) else { return }
        resultCount = Int(beatsPerMinute)

        DispatchQueue.main.async {
            completion(Double(resultCount))
        }
    }
    healthStore.execute(query)
}

注意: .discreteMostRecent 选项仅适用于 iOS 12 或更高版本。