Jason Clutterbuck
Jason Clutterbuck

Reputation: 59

How to sensibly get data out of HealthKits HKSample when returned by a query in swift

I have had a look around the internet and also had a read of what seems relevant in the documentation at developer.apple.com. there are a few tutorials around dealing with how to set up queries but i have not found any easy way to extract the data values from HKSamples returned by any query. Im sure there must be something more elegant and versatile than string processing in this case.

heres the code i have which works well for me:

var anchor : HKQueryAnchor? = nil

func newStreamingQuery(withIdentifier: HKQuantityTypeIdentifier) {
        let hkqType = HKQuantityType.quantityType(forIdentifier: withIdentifier)!
        let observer = HKObserverQuery(sampleType: hkqType, predicate: nil, updateHandler:
            {(queryResult, completionHandler, error) in
            if (error != nil) { print( error!.localizedDescription) ; return}
                // We recreate the query every time becuase it can only be used once.
                let query =  HKAnchoredObjectQuery(type: hkqType, predicate: nil, anchor: self.anchor, limit: HKObjectQueryNoLimit, resultsHandler: { (query, samples, deleted, newAnchor, error) in
                    if error != nil {print(error!) ; return}
                    self.anchor = newAnchor
                    print ("\(samples!.count)\n")
                    for i in ( 0..<samples!.count)
                    {  // What do i do to access the data in s sensible fassion.
                        let hktype = samples![i]
                        let value = hktype// do something with hktype to get the value out
                        let time = hktype// do something with hktype to get the time out
                        print("\(value)\n")}
                  completionHandler()
                })

            WatchHelthKitHelper.healthStore.execute(query)
            })
        WatchHelthKitHelper.healthStore.execute(observer)
    }

If I call it like this:

func startStreamingQuery(){
    newStreamingQuery(withIdentifier: HKQuantityTypeIdentifier.heartRate)
}

I get nice output like this:

1

1.56667 count/s 723404AC-C90C-4374-B75A-AAE7CD166115 "Jason’s Apple Watch" (3.1) "Apple Watch"  (2017-01-02 15:59:42 +0800 - 2017-01-02 15:59:42 +0800)

1

1.63333 count/s 148B311D-57EE-4D65-B560-765E7E8319C6 "Jason’s Apple Watch" (3.1) "Apple Watch"  (2017-01-02 15:59:46 +0800 - 2017-01-02 15:59:46 +0800)

1

1.65 count/s F92DD3AE-0527-48D1-B75B-3F04D6C0ABCF "Jason’s Apple Watch" (3.1) "Apple Watch"  (2017-01-02 15:59:49 +0800 - 2017-01-02 15:59:49 +0800)

1

1.63333 count/s 0CF55099-6D51-408D-B322-00A8F469AF54 "Jason’s Apple Watch" (3.1) "Apple Watch"  (2017-01-02 15:59:53 +0800 - 2017-01-02 15:59:53 +0800)

1

1.48333 count/s 1FCD3472-081F-4479-80F2-543A45CCA221 "Jason’s Apple Watch" (3.1) "Apple Watch"  (2017-01-02 16:00:00 +0800 - 2017-01-02 16:00:00 +0800)

Im sure it is easy to do this but i feel it must be hidden under a concept i do not understand at the moment.

Much gratitude for your answers.

Also if anyone knows how to get more detailed heart wave/pulse data id love to hear about it.

Upvotes: 3

Views: 2881

Answers (1)

Sivajee Battina
Sivajee Battina

Reputation: 4174

This might work for you.

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

Upvotes: 5

Related Questions