iosswifthealthkithksamplequery

Get an array of Blood Glucose records from HealthKit


I'm following some tutorials on HealthKit using swift, one of the tutorials I'm following is how to retrieve some data from the HealthKit such as weight, height age. The tutorial shows how to retrieve the most recent record for each them, the following codes shows that:

func readMostRecentSample(sampleType:HKSampleType , completion: ((HKSample!, NSError!) -> Void)!)
{

// 1. Build the Predicate
let past = NSDate.distantPast() as! NSDate
let now   = NSDate()
let mostRecentPredicate = HKQuery.predicateForSamplesWithStartDate(past, endDate:now, options: .None)

// 2. Build the sort descriptor to return the samples in descending order
let sortDescriptor = NSSortDescriptor(key:HKSampleSortIdentifierStartDate, ascending: false)
// 3. we want to limit the number of samples returned by the query to just 1 (the most recent)
let limit = 1

// 4. Build samples query
let sampleQuery = HKSampleQuery(sampleType: sampleType, predicate: mostRecentPredicate, limit: limit, sortDescriptors: [sortDescriptor])
  { (sampleQuery, results, error ) -> Void in

    if let queryError = error {
      completion(nil,error)
      return;
    }

    // Get the first sample
    let mostRecentSample = results.first as? HKQuantitySample

    // Execute the completion closure
    if completion != nil {
      completion(mostRecentSample,nil)
    }
}
// 5. Execute the Query
self.healthKitStore.executeQuery(sampleQuery)
}

Then in other class the developer passes the parameters to get the required most recent record, the following code shows the method that retrieves the height record:

func updateHeight()
{
// 1. Construct an HKSampleType for Height
let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)

// 2. Call the method to read the most recent Height sample
self.healthManager?.readMostRecentSample(sampleType, completion: { (mostRecentHeight, error) -> Void in

  if( error != nil )
  {
    println("Error reading height from HealthKit Store: \(error.localizedDescription)")
    return;
  }

  var heightLocalizedString = self.kUnknownString;
  self.height = mostRecentHeight as? HKQuantitySample;
  // 3. Format the height to display it on the screen
  if let meters = self.height?.quantity.doubleValueForUnit(HKUnit.meterUnit()) {
    let heightFormatter = NSLengthFormatter()
    heightFormatter.forPersonHeightUse = true;
    heightLocalizedString = heightFormatter.stringFromMeters(meters);
  }


  // 4. Update UI. HealthKit use an internal queue. We make sure that we interact with the UI in the main thread
  dispatch_async(dispatch_get_main_queue(), { () -> Void in
    self.heightLabel.text = heightLocalizedString
    self.updateBMI()
  });
})

}

I created a similar method to the first one, but with few changes so I can get an array of 10 glucose records:

func readAllGlucose(sampleType:HKSampleType , completion: (([HKSample!], NSError!) -> Void)!)
{

    let now   = NSDate()
    let df = NSDateFormatter()
    df.dateFormat = "yyyy-MM-dd"
    let pastt = df.dateFromString("2015-05-18")

    //let mostRecentPredicate = HKQuery.predicateForSamplesWithStartDate(past, endDate:now, options: .None)
    let allreadings = HKQuery.predicateForSamplesWithStartDate(pastt, endDate: now, options: .None)

    // 2. Build the sort descriptor to return the samples in descending order
    let sortDescriptor = NSSortDescriptor(key:HKSampleSortIdentifierStartDate, ascending: false)
    // 3. we want to limit the number of samples returned by the query to just 1 (the most recent)
    let limit = 10

    // 4. Build samples query

    let sampleQuery = HKSampleQuery(sampleType: sampleType, predicate: allreadings, limit: limit, sortDescriptors: [sortDescriptor])
        { (sampleQuery, results, error ) -> Void in

            if let queryError = error {
                completion([nil],error)
                return;
            }

            // Get the first sample
            let allSamples = results as? [HKQuantitySample]

            // Execute the completion closure
            if completion != nil {
                completion(allSamples!,nil)
            }
    }
    // 5. Execute the Query
    self.healthKitStore.executeQuery(sampleQuery)
}

Then I created another method similar to updateHeight() method,but of course with doing the necessary changes:

func updateLastGlucoRecords()
{
    // 1. Construct an HKSampleType for weight
    let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBloodGlucose)

    // 2. Call the method to read the most recent weight sample
    self.healthManager?.readAllGlucose(sampleType, completion: {([allReadings], error) -> Void in

        if (error != nil) {
            println("Error reading glucose readings from HealthKit Store: \(error.localizedDescription)")
            return;
        }

        var glucoseLocalizedString = self.kUnknownString;
        self.glucose = allReadings as? [HKQuantitySample]
        for reading in readings {

            if let record = reading.quantity {
                glucoseLocalizedString = record
            }
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.glucoReadings.append("\(glucoseLocalizedString)")
            })

        }


    })
    self.healthManager?.readMostRecentSample(sampleType, completion: { (mostRecentWeight, error) -> Void in

        if( error != nil )
        {
            println("Error reading weight from HealthKit Store: \(error.localizedDescription)")
            return;
        }

        var weightLocalizedString = self.kUnknownString;
        // 3. Format the weight to display it on the screen
        self.weight = mostRecentWeight as? HKQuantitySample;
        if let kilograms = self.weight?.quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo)) {
            let weightFormatter = NSMassFormatter()
            weightFormatter.forPersonMassUse = true;
            weightLocalizedString = weightFormatter.stringFromKilograms(kilograms)
        }

        // 4. Update UI in the main thread
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.weightLabel.text = weightLocalizedString
            self.updateBMI()

        });
    });
}

But unfortunately I'm getting two errors at the line:

self.healthManager?.readAllGlucose(sampleType, completion: {([allReadings], error) -> Void in

first error:

[HKSample!]' is not a subtype of '<>

second error:

Use of undeclared type 'allReadings'

If someone have any idea that could solve this problem I will be thankful and grateful for that

thanks in advance


Solution

  • I think the issue is your use of square brackets around allReadings in ([allReadings], error). Try removing them. You shouldn't need to indicate that allReadings is an array. That will be inferred by the compiler because the first parameter of the closure is an array.