Reputation: 5215
I have an iOS app that I'm developing in Swift, and as part of the app it gathers the step count for the current day.
The first time I run the app, the count is "0", but if I click a button in the interface to re-run this function that queries HK, then the correct number appears.
I am guessing this is because HK needs some time to gather the data, or something, but I'm not sure how to fix it. Maybe HK can fire an event when the data is ready, and then I can update the UI?
Here's the routine that gathers the data from HK. This function executes immediately when the app start (and it shows "0 steps today"), and then as I describe above, I can tap a button to execute the function again (and then I get the right number).
func queryStepsSum() {
// prepare HK for the data
let endDate = NSDate() // right now
let startDate = NSCalendar.currentCalendar().dateBySettingHour(0, minute: 0, second: 0, ofDate: endDate, options: NSCalendarOptions())
let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: .None)
let sumOption = HKStatisticsOptions.CumulativeSum
let statisticsSumQuery = HKStatisticsQuery( quantityType: self.stepsCount!, quantitySamplePredicate: predicate,
options: sumOption)
{ [unowned self] (query, result, error) in
if let sumQuantity = result?.sumQuantity() {
self.numberOfSteps = Int(sumQuantity.doubleValueForUnit(HKUnit.countUnit()))
}
}
// run the HK query
self.healthStore?.executeQuery(statisticsSumQuery)
// update the UI with the result
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.stepsLabel.text = "\(self.numberOfSteps) steps today";
});
}
Upvotes: 2
Views: 374
Reputation: 7343
Your code doesn't wait for the query to finish before displaying the result (the query happens asynchronously). You should update your UI from the query's result handler, like this:
let statisticsSumQuery = HKStatisticsQuery( quantityType: self.stepsCount!, quantitySamplePredicate: predicate,
options: sumOption)
{ [unowned self] (query, result, error) in
dispatch_async(dispatch_get_main_queue()) {
if let sumQuantity = result?.sumQuantity() {
self.numberOfSteps = Int(sumQuantity.doubleValueForUnit(HKUnit.countUnit()))
self.stepsLabel.text = "\(self.numberOfSteps) steps today";
}
}
}
Also note that I've included a dispatch back to the main thread since the query results handler runs on a background thread and it's not safe to manipulate UI in that context.
Upvotes: 2
Reputation: 325
Are you calling your function in viewDidLoad? You might try calling it in viewDidAppear instead. If that doesn't work maybe there is some sort of delegate method that can update you when the data is ready like you said. I've never worked with HealthKit but I'll check to see if I can find anything.
EDIT: This might set the UI component off the background thread. Try:
var numberOfSteps: Int! {
didSet {
self.stepsLabel.text = "\(self.numberOfSteps) steps today"
}
}
That should get rid of the error that you're updating the UI on the background thread. Also make sure to remove your call in the closure that I told you to put.
Upvotes: 0