【问题标题】:How to read heart rate from iOS HealthKit app using Swift?如何使用 Swift 从 iOS HealthKit 应用程序读取心率?
【发布时间】: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”类型的初始化器

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

【问题讨论】:

    标签: ios swift healthkit hkhealthstore


    【解决方案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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多