如何使用 Swift 从 iOS HealthKit 应用程序读取心率?

Posted

技术标签:

【中文标题】如何使用 Swift 从 iOS HealthKit 应用程序读取心率?【英文标题】:How to read heart rate from iOS HealthKit app using Swift? 【发布时间】:2015-09-10 04:50:04 【问题描述】:

我正在使用以下 Swift 代码。

let sampleType : HKSampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)
let nowDate: NSDate = NSDate()
var calendar: NSCalendar = NSCalendar.autoupdatingCurrentCalendar()

let yearMonthDay: NSCalendarUnit = NSCalendarUnit.YearCalendarUnit | NSCalendarUnit.MonthCalendarUnit | NSCalendarUnit.DayCalendarUnit

var components: NSDateComponents = calendar.components(yearMonthDay , fromDate: nowDate)
var beginOfDay : NSDate = calendar.dateFromComponents(components)!
var predicate : NSPredicate = HKQuery.predicateForSamplesWithStartDate(beginOfDay, endDate: nowDate, options: HKQueryOptions.StrictStartDate)

let squery: HKStatisticsQuery = HKStatisticsQuery(quantityType: sampleType, quantitySamplePredicate: predicate, options: HKStatisticsOptions.None)  (qurt, resul, errval) -> Void in

    dispatch_async( dispatch_get_main_queue(),  () -> Void in
        var quantity : HKQuantity = result.averageQuantity;
        var beats : double = quantity.doubleValueForUnit(HKUnit.heartBeatsPerMinuteUnit())
        // [quantity doubleValueForUnit:[HKUnit heartBeatsPerMinuteUnit]];
         self.txtfldHeartRate.text = "\(beats)"
    )



healthManager.healthKitStore.executeQuery(squery)

我收到以下错误消息:

找不到接受类型为“(quantityType: HKSampleType, quantitySamplePredicate: NSPredicate, options: HKStatisticsOptions, (_, _, _) -> Void)”的参数列表的“HKStatisticsQuery”类型的初始化器

请告诉我如何解决这个问题。

【问题讨论】:

【参考方案1】:

从 ViewController 读取数据(不是 Apple Watch 扩展)

斯威夫特 5

let health: HKHealthStore = HKHealthStore()
let heartRateUnit:HKUnit = HKUnit(from: "count/min")
let heartRateType:HKQuantityType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
    var heartRateQuery:HKSampleQuery?

/*Method to get todays heart rate - this only reads data from health kit. */
 func getTodaysHeartRates() 
    //predicate
    let calendar = NSCalendar.current
    let now = NSDate()
    let components = calendar.dateComponents([.year, .month, .day], from: now as Date)
    
    guard let startDate:NSDate = calendar.date(from: components) as NSDate? else  return 
    var dayComponent    = DateComponents()
    dayComponent.day    = 1
    let endDate:NSDate? = calendar.date(byAdding: dayComponent, to: startDate as Date) as NSDate?
    let predicate = HKQuery.predicateForSamples(withStart: startDate as Date, end: endDate as Date?, options: [])

    //descriptor
    let sortDescriptors = [
                            NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
                          ]
    
    heartRateQuery = HKSampleQuery(sampleType: heartRateType, predicate: predicate, limit: 25, sortDescriptors: sortDescriptors, resultsHandler:  (query, results, error) in
        guard error == nil else  print("error"); return 

        self.printHeartRateInfo(results: results)
    ) //eo-query
    
    health.execute(heartRateQuery!)
 //eom

/*used only for testing, prints heart rate info */
private func printHeartRateInfo(results:[HKSample]?)

    for (_, sample) in results!.enumerated() 
        guard let currData:HKQuantitySample = sample as? HKQuantitySample else  return 

        print("[\(sample)]")
        print("Heart Rate: \(currData.quantity.doubleValue(for: heartRateUnit))")
        print("quantityType: \(currData.quantityType)")
        print("Start Date: \(currData.startDate)")
        print("End Date: \(currData.endDate)")
        print("Metadata: \(currData.metadata)")
        print("UUID: \(currData.uuid)")
        print("Source: \(currData.sourceRevision)")
        print("Device: \(currData.device)")
        print("---------------------------------\n")
    //eofl
//eom

斯威夫特 3

let health: HKHealthStore = HKHealthStore()
let heartRateUnit:HKUnit = HKUnit(fromString: "count/min")
let heartRateType:HKQuantityType   = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
var heartRateQuery:HKSampleQuery?


/*Method to get todays heart rate - this only reads data from health kit. */
 func getTodaysHeartRates()
    
        //predicate
        let calendar = NSCalendar.currentCalendar()
        let now = NSDate()
        let components = calendar.components([.Year,.Month,.Day], fromDate: now)
        guard let startDate:NSDate = calendar.dateFromComponents(components) else  return 
        let endDate:NSDate? = calendar.dateByAddingUnit(.Day, value: 1, toDate: startDate, options: [])
        let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: .None)
        
        //descriptor
        let sortDescriptors = [
                                NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
                              ]
        
        heartRateQuery = HKSampleQuery(sampleType: heartRateType,
                                        predicate: predicate,
                                        limit: 25,
                                        sortDescriptors: sortDescriptors)
             (query:HKSampleQuery, results:[HKSample]?, error:NSError?) -> Void in
                
                guard error == nil else  print("error"); return 

                //self.printHeartRateInfo(results)
                
                self.updateHistoryTableViewContent(results)

        //eo-query
        health.executeQuery(heartRateQuery!)
        
   //eom

/*used only for testing, prints heart rate info */
private func printHeartRateInfo(results:[HKSample]?)
    
        for(var iter = 0 ; iter < results!.count; iter++)
        
            guard let currData:HKQuantitySample = results![iter] as? HKQuantitySample else  return 
            
            print("[\(iter)]")
            print("Heart Rate: \(currData.quantity.doubleValueForUnit(heartRateUnit))")
            print("quantityType: \(currData.quantityType)")
            print("Start Date: \(currData.startDate)")
            print("End Date: \(currData.endDate)")
            print("Metadata: \(currData.metadata)")
            print("UUID: \(currData.UUID)")
            print("Source: \(currData.sourceRevision)")
            print("Device: \(currData.device)")
            print("---------------------------------\n")
        //eofl
    //eom

使用 Apple Watch 扩展读取数据:

要在 Apple Watch 中执行查询,请执行以下操作:

        heartRateQuery = self.createStreamingQuery()
        health.executeQuery(heartRateQuery!)

不要忘记属性:

let health: HKHealthStore = HKHealthStore()
let heartRateUnit:HKUnit = HKUnit(fromString: "count/min")
let heartRateType:HKQuantityType   = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
var heartRateQuery:HKQuery?

/*下面的方法没有限制,一旦执行查询就无限查询heart */

private func createStreamingQuery() -> HKQuery
    
        let queryPredicate  = HKQuery.predicateForSamplesWithStartDate(NSDate(), endDate: nil, options: .None)
        
    let query:HKAnchoredObjectQuery = HKAnchoredObjectQuery(type: self.heartRateType, predicate: queryPredicate, anchor: nil, limit: Int(HKObjectQueryNoLimit))
     (query:HKAnchoredObjectQuery, samples:[HKSample]?, deletedObjects:[HKDeletedObject]?, anchor:HKQueryAnchor?, error:NSError?) -> Void in
    
        if let errorFound:NSError = error
        
            print("query error: \(errorFound.localizedDescription)")
        
        else
        
            //printing heart rate
             if let samples = samples as? [HKQuantitySample]
              
                 if let quantity = samples.last?.quantity
                 
                     print("\(quantity.doubleValueForUnit(heartRateUnit))")
                 
               
        
    //eo-query
    
    query.updateHandler =
         (query:HKAnchoredObjectQuery, samples:[HKSample]?, deletedObjects:[HKDeletedObject]?, anchor:HKQueryAnchor?, error:NSError?) -> Void in
            
            if let errorFound:NSError = error
            
                print("query-handler error : \(errorFound.localizedDescription)")
            
            else
            
                  //printing heart rate
                  if let samples = samples as? [HKQuantitySample]
                  
                       if let quantity = samples.last?.quantity
                       
                          print("\(quantity.doubleValueForUnit(heartRateUnit))")
                       
                  
            //eo-non_error
    //eo-query-handler
    
    return query
//eom

如何申请授权?

func requestAuthorization()
    
    //reading
    let readingTypes:Set = Set( [heartRateType] )
    
    //writing
    let writingTypes:Set = Set( [heartRateType] )
    
    //auth request
    health.requestAuthorizationToShareTypes(writingTypes, readTypes: readingTypes)  (success, error) -> Void in
        
        if error != nil
        
            print("error \(error?.localizedDescription)")
        
        else if success
        
            
        
    //eo-request
//eom

【讨论】:

【参考方案2】:

HKStatisticsQuery 不会是我的首选。它用于统计计算(即最小值、最大值、平均值、总和)。

你可以使用简单的HKQuery:

  public func fetchLatestHeartRateSample(
    completion: @escaping (_ samples: [HKQuantitySample]?) -> Void) 

    /// Create sample type for the heart rate
    guard let sampleType = HKObjectType
      .quantityType(forIdentifier: .heartRate) else 
        completion(nil)
      return
    

    /// Predicate for specifiying start and end dates for the query
    let predicate = HKQuery
      .predicateForSamples(
        withStart: Date.distantPast,
        end: Date(),
        options: .strictEndDate)

    /// Set sorting by date.
    let sortDescriptor = NSSortDescriptor(
      key: HKSampleSortIdentifierStartDate,
      ascending: false)

    /// Create the query
    let query = HKSampleQuery(
      sampleType: sampleType,
      predicate: predicate,
      limit: Int(HKObjectQueryNoLimit),
      sortDescriptors: [sortDescriptor])  (_, results, error) in

        guard error == nil else 
          print("Error: \(error!.localizedDescription)")
          return
        


        completion(results as? [HKQuantitySample])
    

    /// Execute the query in the health store
    let healthStore = HKHealthStore()
    healthStore.execute(query)
  

【讨论】:

谢谢!它节省了我的时间。【参考方案3】:

在初始化期间指定常量和变量的类型在 Swift 中通常是多余的,就像在您的情况下,您指定了父类 HKSampleType 类型而不是其子类 HKQuantityType。因此,在您的情况下,只需省略类型声明:

let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
let nowDate = NSDate()
var calendar = NSCalendar.autoupdatingCurrentCalendar()

如果您使用 Swift 2.0,您还应该在下一行使用类似数组的语法:

let yearMonthDay: NSCalendarUnit = [NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day]

【讨论】:

【参考方案4】:

尝试这种方式,在 Xcode 6.4 中移动完成处理程序似乎为我解决了这个问题-

let squery = HKStatisticsQuery(quantityType: sampleType, quantitySamplePredicate: predicate, options: HKStatisticsOptions.None, completionHandler:  (qurt, result, errval) -> Void in

  dispatch_async( dispatch_get_main_queue(),  () -> Void in

    var quantity : HKQuantity = result.averageQuantity();
    var beats : Double = quantity.doubleValueForUnit(HKUnit.atmosphereUnit())
    // [quantity doubleValueForUnit:[HKUnit heartBeatsPerMinuteUnit]];
  )
)

注意:我在闭包中看到了一些编译器错误,因此更改了 2 行以确保编译-

var quantity : HKQuantity = result.averageQuantity();
var beats : Double = quantity.doubleValueForUnit(HKUnit.atmosphereUnit())

【讨论】:

【参考方案5】:

您应该在查询中使用HKQuantityType 而不是HKSampleType

let squery: HKStatisticsQuery = HKStatisticsQuery(quantityType: HKQuantityTypeIdentifierHeartRate, quantitySamplePredicate: predicate, options: HKStatisticsOptions.None)  (qurt, resul, errval) -> Void in

【讨论】:

以上是关于如何使用 Swift 从 iOS HealthKit 应用程序读取心率?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 swift iOS 中使用 swift 高阶函数从本地 json 创建 ViewModel

如何使用 Swift 从 iOS HealthKit 应用程序读取心率?

如何使用 Swift 从 iOS HealthKit 应用程序读取心率?

如何在 IOS 上使用 Swift 解析 JSON,从 PHP 服务脚本发送?

如何使用iOS和Swift从Google SDK获取附近的地点?

如何在iOS Swift 3中从键盘中删除更改语言键按钮