I am trying to get last 7 days step count but it is always coming zero. But when I open the health app in iPhone then it is more than 3000 steps. Even I also added property Privacy - Health Share Usage Description and Privacy - Health Update Usage Description in .plist file.
Here is my code
var healthScore = HKHealthStore()
override func viewDidLoad() {
super.viewDidLoad()
// Access Step Count
let healthKitTypes: Set = [ HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)! ]
// Check for Authorization
healthScore.requestAuthorization(toShare: healthKitTypes, read: healthKitTypes) { (bool, error) in
if (bool) {
// Authorization Successful
self.getSteps { (result) in
DispatchQueue.main.async {
let stepCount = String(Int(result))
self.stepLbl.text = String(stepCount)
}
}
}
}
}
func getSteps(completion: #escaping (Double) -> Void){
let stepsQuantityType = HKQuantityType.quantityType(forIdentifier: .stepCount)!
let now = Date()
let exactlySevenDaysAgo = Calendar.current.date(byAdding: DateComponents(day: -7), to: now)!
let predicate = HKQuery.predicateForSamples(withStart: exactlySevenDaysAgo, end: now, options: .strictStartDate)
let query = HKStatisticsQuery(quantityType: stepsQuantityType, quantitySamplePredicate: predicate, options: .cumulativeSum) { (_, result, error) in
var resultCount = 0.0
guard let result = result else {
print("\(String(describing: error?.localizedDescription)) ")
completion(resultCount)
return
}
if let sum = result.sumQuantity() {
resultCount = sum.doubleValue(for: HKUnit.count())
}
DispatchQueue.main.async {
completion(resultCount)
}
}
healthScore.execute(query)
}
In console I checked the dates are also correct now here's the screenshot
Related
I am now analyzing swift source code.
In this source code, performQuery is defined as function, but in line 2, performQuery is used without bracket"()". What does it mean?
Can we use a function without bracket?
I have read all the swift grammar but I cannot find similar code.
Is it related to "Unstructured Concurrency"?
==================================================
func calculateDailyQuantitySamplesForPastWeek() {
performQuery {
DispatchQueue.main.async { [weak self] in
self?.reloadData()
}
}
}
// MARK: - HealthQueryDataSource
func performQuery(completion: #escaping () -> Void) {
let predicate = createLastWeekPredicate()
let anchorDate = createAnchorDate()
let dailyInterval = DateComponents(day: 1)
let statisticsOptions = getStatisticsOptions(for: dataTypeIdentifier)
let query = HKStatisticsCollectionQuery(quantityType: quantityType,
quantitySamplePredicate: predicate,
options: statisticsOptions,
anchorDate: anchorDate,
intervalComponents: dailyInterval)
// The handler block for the HKStatisticsCollection object.
let updateInterfaceWithStatistics: (HKStatisticsCollection) -> Void = { statisticsCollection in
self.dataValues = []
let now = Date()
let startDate = getLastWeekStartDate()
let endDate = now
statisticsCollection.enumerateStatistics(from: startDate, to: endDate) { [weak self] (statistics, stop) in
var dataValue = HealthDataTypeValue(startDate: statistics.startDate,
endDate: statistics.endDate,
value: 0)
if let quantity = getStatisticsQuantity(for: statistics, with: statisticsOptions),
let identifier = self?.dataTypeIdentifier,
let unit = preferredUnit(for: identifier) {
dataValue.value = quantity.doubleValue(for: unit)
}
self?.dataValues.append(dataValue)
}
completion()
}
query.initialResultsHandler = { query, statisticsCollection, error in
if let statisticsCollection = statisticsCollection {
updateInterfaceWithStatistics(statisticsCollection)
}
}
query.statisticsUpdateHandler = { [weak self] query, statistics, statisticsCollection, error in
// Ensure we only update the interface if the visible data type is updated
if let statisticsCollection = statisticsCollection, query.objectType?.identifier == self?.dataTypeIdentifier {
updateInterfaceWithStatistics(statisticsCollection)
}
}
self.healthStore.execute(query)
self.query = query
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let query = query {
self.healthStore.stop(query)
}
}
}
you need to learn closure. please check the link
I have a CKRecord of recipes that gets fetched to an iOS app. Once I have that list, I need to prioritize the results of recipes that are the highest suggested "likedIds" which is a list of integers representing recipe_ids (please see my dataset image below), then display the remaining recipes below that. I can't merely sort by highest rated recipes because I'm using collaborative filtering elsewhere in the project to suggest specific recipes over others, but I still want to list them all.
Here in this code below I am appending the results of NSPredicates to a list of CKQuery called 'queries'. Now that I have that [CKquery], what do I do with it? How do I fetch the results I need? Which method do I use, if publicDB.perform() isn't the right method (since I get an 'expected argument type' error)? Below, I tried using a for loop inside of the AttachToMainThread() function that I wrote, but I get 3 different random results at refresh, recipes in the "likedIds" list, recipes not the "likedIds" list, or nothing at all, yet no SIGABRT errors which is nice.
TL;DR
What do I do with my CKquery list to fetch results?
Thank you for your time!
Just the code focusing on the primary subject:
import Foundation
import CloudKit
class Model {
// MARK: - iCloud Info
let container: CKContainer
let publicDB: CKDatabase
private(set) var recipes: [Recipe] = []
static var currentModel = Model()
init() {
container = CKContainer.default()
publicDB = container.publicCloudDatabase
privateDB = container.privateCloudDatabase
}
#objc func refresh(_ completion: #escaping (Error?) -> Void) {
var queries = [CKQuery] ()
// Function that returns a CKQuery
let likedQuery = GetRecipesWithLikedIds()
queries.append(likedQuery)
// Function that returns a CKQuery
let unlikedQuery = GetRecipesWithoutLikedIds()
queries.append(unlikedQuery)
AttachToMainThread(forQuery: queries, completion)
}
private func AttachToMainThread(forQuery queries: [CKQuery],
_ completion: #escaping (Error?) -> Void) {
for q in queries {
publicDB.perform(q,
inZoneWith: CKRecordZone.default().zoneID) { [weak self] results, error in
guard let self = self else { return }
if let error = error {
DispatchQueue.main.async {
completion(error)
}
return
}
guard let results = results else { return }
self.recipes = results.compactMap {
Recipe(record: $0, database: self.publicDB)
}
DispatchQueue.main.async {
completion(nil)
}
}
}
}
}
My entire code:
import Foundation
import CloudKit
class Model {
// MARK: - iCloud Info
let container: CKContainer
let publicDB: CKDatabase
var carbohydrate = "rice"
var vegetable = "tomatoes"
// MARK: - Properties
private(set) var recipes: [Recipe] = []
static var currentModel = Model()
init() {
container = CKContainer.default()
publicDB = container.publicCloudDatabase
privateDB = container.privateCloudDatabase
}
#objc func refresh(_ completion: #escaping (Error?) -> Void) {
var queries = [CKQuery] ()
let likedQuery = GetRecipesWithLikedIds()
queries.append(likedQuery)
let unlikedQuery = GetRecipesWithoutLikedIds()
queries.append(unlikedQuery)
AttachToMainThread(forQuery: queries, completion)
}
private func AttachToMainThread(forQuery queries: [CKQuery],
_ completion: #escaping (Error?) -> Void) {
for q in queries {
publicDB.perform(q,
inZoneWith: CKRecordZone.default().zoneID) { [weak self] results, error in
guard let self = self else { return }
if let error = error {
DispatchQueue.main.async {
completion(error)
}
return
}
guard let results = results else { return }
self.recipes = results.compactMap {
Recipe(record: $0, database: self.publicDB)
}
for r in self.recipes {
self.PrettyPrintRecipes(rName: r.name, rId: String(r.recipe_id), rIng: r.ingredients)
}
DispatchQueue.main.async {
completion(nil)
}
}
}
}
func GetRecipesWithLikedIds() -> CKQuery {
let searchTextA: [String] = [carbohydrate," "+carbohydrate,carbohydrate+"s",carbohydrate+"es"]
let subPred1 = NSPredicate (format: "ANY ingredients IN %#",argumentArray: [searchTextA])
let searchTextB: [String] = [vegetable," "+vegetable,vegetable+"s",vegetable+"es"]
let subPred2 = NSPredicate (format: "ANY ingredients IN %#",argumentArray: [searchTextB])
let likedIds: [Int] = [13733,32441]
let subPred3 = NSPredicate (format: "NOT (recipe_id IN %#)", likedIds)
let and_pred1 = NSCompoundPredicate(andPredicateWithSubpredicates: [subPred1, subPred2])
let and_pred2 = NSCompoundPredicate(andPredicateWithSubpredicates: [subPred3])
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [and_pred1, and_pred2])
return CKQuery(recordType: "Recipe", predicate: predicate)
}
func GetRecipesWithoutLikedIds() -> CKQuery {
let searchTextA: [String] = [carbohydrate," "+carbohydrate,carbohydrate+"s",carbohydrate+"es"]
let subPred1 = NSPredicate (format: "ANY ingredients IN %#",argumentArray: [searchTextA])
let searchTextB: [String] = [vegetable," "+vegetable,vegetable+"s",vegetable+"es"]
let subPred2 = NSPredicate (format: "ANY ingredients IN %#",argumentArray: [searchTextB])
let likedIds: [Int] = [13733,32441]
let subPred3 = NSPredicate (format: "recipe_id IN %#",argumentArray: [likedIds])
let and_pred1 = NSCompoundPredicate(andPredicateWithSubpredicates: [subPred1, subPred2])
let and_pred2 = NSCompoundPredicate(andPredicateWithSubpredicates: [subPred3])
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [and_pred1, and_pred2])
return CKQuery(recordType: "Recipe", predicate: predicate)
}
func PrettyPrintRecipes(rName: String, rId: String, rIng: [String]) {
print("Name: "+rName)
print("Recipe_id: "+rId)
print("Ingredients:")
for s in 0..<rIng.count {
print("\t"+String(s)+": "+rIng[s])
}
}
public func printVegetable(){
print(vegetable)
}
}
An Example Image of my Dataset
This question already has answers here:
How to notify a queue in Swift (GCD)
(2 answers)
Closed 4 years ago.
I have this identical code in another app and it works without fail, now in this app the dispatch group is not notifying and my handler isn't getting called? I can't figure out the difference between the 2 apps since the code is identical?
func getHeartRateMaxFromWorkouts(workouts: [HKWorkout], handler: #escaping (careerMaxHeartRatePerWorkoutAsCustomHistoricalSample, careerAverageHeartRatePerWorkoutAsCustomHistoricalSample) -> Void) {
let workoutsReversed = workouts.reversed()
guard let heartRateType:HKQuantityType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) else { return }
let heartRateUnit:HKUnit = HKUnit(from: "count/min")
var heartRateMaxArrayAsCustomHistoricalSample = [CustomHistoricalSample]()
var heartRateAvgArrayAsCustomHistoricalSample = [CustomHistoricalSample]()
//DispatchGroup needed since making async call per workout and need notified when all calls are done
let dispatchGroup = DispatchGroup()
for workout in workoutsReversed {
//predicate
let startDate = workout.startDate
let endDate = workout.endDate
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
//descriptor
let sortDescriptors = [
NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: true) //Changed this to false so that HRR and MCS would calculate, always check this if not getting these values
]
dispatchGroup.enter()
let heartRateQuery = HKSampleQuery(sampleType: heartRateType,
predicate: predicate,
limit: (HKObjectQueryNoLimit),
sortDescriptors: sortDescriptors)
{ (query:HKSampleQuery, results:[HKSample]?, error:Error?) -> Void in
guard error == nil else { print("get heart rate error"); return }
guard let unwrappedResults = results as? [HKQuantitySample] else { print("get heart rate error"); return}
let heartRatesAsDouble = unwrappedResults.map {$0.quantity.doubleValue(for: heartRateUnit)}
guard let max = heartRatesAsDouble.max() else { return }
let maxAsCustomHistoricalSample = CustomHistoricalSample(value: max, date: workout.startDate)
heartRateMaxArrayAsCustomHistoricalSample.append(maxAsCustomHistoricalSample)
let average = heartRatesAsDouble.average
let averageAsCustomHistoricalSample = CustomHistoricalSample(value: average, date: workout.startDate)
heartRateAvgArrayAsCustomHistoricalSample.append(averageAsCustomHistoricalSample)
dispatchGroup.leave()
}
healthStore.execute(heartRateQuery)
} //End of for workout loop
dispatchGroup.notify(queue: .main) {
//Need to sort by date since the dates come back jumbled
let sortedReversedHeartRateMaxArrayAsCustomHistoricalSampple = heartRateMaxArrayAsCustomHistoricalSample.sorted { $0.date > $1.date }.reversed() as [CustomHistoricalSample]
let sortedReversedHeartRateAverageArrayAsCustomHistoricalSampple = heartRateAvgArrayAsCustomHistoricalSample.sorted { $0.date > $1.date }.reversed() as [CustomHistoricalSample]
print("handler called = \(sortedReversedHeartRateMaxArrayAsCustomHistoricalSampple.count)")
handler(sortedReversedHeartRateMaxArrayAsCustomHistoricalSampple, sortedReversedHeartRateAverageArrayAsCustomHistoricalSampple)
}
} //End getHeartRateMaxFromWorkouts
It's a good practice to make leave top of callback
guard error == nil else { print("get heart rate error"); dispatchGroup.leave() return ; }
guard let unwrappedResults = results as? [HKQuantitySample] else { print("get heart rate error"); dispatchGroup.leave(); return}
let heartRatesAsDouble = unwrappedResults.map {$0.quantity.doubleValue(for: heartRateUnit)}
guard let max = heartRatesAsDouble.max() else { dispatchGroup.leave(); return }
let maxAsCustomHistoricalSample = CustomHistoricalSample(value: max, date: workout.startDate)
heartRateMaxArrayAsCustomHistoricalSample.append(maxAsCustomHistoricalSample)
let average = heartRatesAsDouble.average
let averageAsCustomHistoricalSample = CustomHistoricalSample(value: average, date: workout.startDate)
dispatchGroup.leave()
heartRateAvgArrayAsCustomHistoricalSample.append(averageAsCustomHistoricalSample)
I want to retrieve the value that indicates whether or not the user has stood this hour. I also want to be able to retrieve the StandHours count for the day.
Here are the Apple links that I've been trying to understand in order get the value from HealthKit. I provide these links to help provide understanding for what I'm looking for and also to help you answer my question.
appleStandHour type property: https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/1615539-applestandhour
HealthKit category type identifier: https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier
HealthKit constants: https://developer.apple.com/documentation/healthkit/healthkit_constants
Bruno's answer is only half of the answer. For example, his standUnit variable is how he pulls the # of hours that the user has stood today. I tested it. Also, I made the assumption that it had to be pulled from within the scope of the summaries variable.
I have found another question on StackOverflow that might provide some clues. I think they managed to pull a value via a HKCategoryTypeIdentifier: Watch os 2.0 beta: access heart beat rate
Here's my attempted code as far as I have been able to get:
import UIKit
import HealthKit
import HealthKitUI
class ViewController: UIViewController {
let hkStoreOnVC : HKHealthStore = HKHealthStore()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
authorizeHealthKit()
hkTest()
hkTest2()
}
func authorizeHealthKit() { //-> Bool {
print("health kit authorize?")
let healthStore = HKHealthStore()
let objectTypes: Set<HKObjectType> = [
HKObjectType.activitySummaryType()
]
healthStore.requestAuthorization(toShare: nil, read: objectTypes) { (success, error) in
// Authorization request finished, hopefully the user allowed access!
print("health kit authorized")
}
}
func hkTest() {
print("health kit test.")
let calendar = Calendar.autoupdatingCurrent
var dateComponents = calendar.dateComponents(
[ .year, .month, .day ],
from: Date()
)
// This line is required to make the whole thing work
dateComponents.calendar = calendar
let predicate = HKQuery.predicateForActivitySummary(with: dateComponents)
//----------------------
let query = HKActivitySummaryQuery(predicate: predicate) { (query, summaries, error) in
print("query")
guard let summaries = summaries, summaries.count > 0
else {
print("no summaries")
return
}
// Handle data
for thisSummary in summaries {
// print("for each summary")
let standUnit = HKUnit.count()
let standHours = thisSummary.appleStandHours.doubleValue(for: standUnit)
print("stand hours \(standHours)")
}//end for
} //end query
}
func hkTest2() {
var isEnabled = true
print ("authorize health kit" )
if HKHealthStore.isHealthDataAvailable() {
let stepsCount = NSSet(objects: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount ) )
for thisValue in stepsCount {
// thisValue.
print("thisValue: \(thisValue)")
}
print(" authorize HK - steps count \(stepsCount) ")
}
// Create the date components for the predicate
guard let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian) else {
fatalError("*** This should never fail. ***")
}
let endDate = NSDate()
guard let startDate = calendar.date(byAdding: .day, value: -7, to: endDate as Date, options: []) else {
fatalError("*** unable to calculate the start date ***")
}
let units: NSCalendar.Unit = [.day, .month, .year, .era]
var startDateComponents = calendar.components(units, from: startDate)
startDateComponents.calendar = calendar as Calendar
var endDateComponents = calendar.components(units, from: endDate as Date)
endDateComponents.calendar = calendar as Calendar
// Create the predicate for the query
let summariesWithinRange = HKQuery.predicate(forActivitySummariesBetweenStart: startDateComponents, end: endDateComponents)
// Build the query
let query = HKActivitySummaryQuery(predicate: summariesWithinRange) { (query, summaries, error) -> Void in
guard let activitySummaries = summaries else {
guard let queryError = error else {
fatalError("*** Did not return a valid error object. ***")
}
// Handle the error here...
return
}
for thisSummary in activitySummaries {
// print("for each summary")
let standUnit = HKUnit.count()
let standHours = thisSummary.appleStandHours.doubleValue(for: standUnit)
// let stoodThisHourMaybe = thisSummary.appleStandHours.categ //doubleValue(for: standUnit)
//\(thisSummary.description) //stand unit _\(standUnit)_
print("day#\(thisSummary.dateComponents(for: calendar as Calendar).day) stand hours \(standHours) ")
}//end for
// Do something with the summaries here...
for thisItem in activitySummaries {
//thisItem.appleStandHours
print("abc \( thisItem.appleStandHours ) " )
}//end for
}
// Run the query
let hkStore : HKHealthStore = HKHealthStore()
hkStore.execute(query)
//***
let aStandHour = HKCategoryType.categoryType(forIdentifier: .appleStandHour)
// This is the type you want updates on. It can be any health kit type, including heart rate.
// let distanceType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.distanceWalkingRunning)
// Match samples with a start date after the workout start
// let predicate = .predicat //( , endDate: nil, options: .None)
// let theDate : Date =
let thepredicate = HKQuery.predicateForCategorySamples(with: .greaterThanOrEqualTo, value: 0) //.predicateForSamplesWithStartDate(startDate , endDate: nil, options: .None)
// predicate
// let predicate = . //(theDate , endDate: nil, options: .None)
let hka : HKQueryAnchor = HKQueryAnchor(fromValue: 0)
let sHourQuery = HKAnchoredObjectQuery(type: aStandHour!, predicate: thepredicate, anchor: hka, limit: 0, resultsHandler: { ( query, samples, deletedObjects, anchor, error) -> Void in
// Handle when the query first returns results
// TODO: do whatever you want with samples (note you are not on the main thread)
print("getting here A?")
// for thisSample in samples! {
// print("A smpLType \(thisSample.sampleType) thisSample \(thisSample)")
// }
})
// This is called each time a new value is entered into HealthKit (samples may be batched together for efficiency)
sHourQuery.updateHandler = { (query, samples, deletedObjects, anchor, error) -> Void in
// Handle update notifications after the query has initially run
// TODO: do whatever you want with samples (note you are not on the main thread)
print("getting here B?")
for thisSample in samples! {
print("B smpLType \(thisSample.sampleType) thisSample \(thisSample)")
}
}
// Start the query
self.hkStoreOnVC.execute(sHourQuery)
//***
}//end func
func myCompletionHandler(bTest: Bool ) {
print("my completion handler")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}//end viewController Class
Here's the code output - the log never prints to "getting here b?":
health kit authorize?
health kit test.
authorize health kit
health kit authorized
thisValue: HKQuantityTypeIdentifierStepCount
authorize HK - steps count {(
HKQuantityTypeIdentifierStepCount
)}
2017-11-04 19:18:30.100562-0500 watchapptest[25048:4695625] refreshPreferences: HangTracerEnabled: 0
2017-11-04 19:18:30.100600-0500 watchapptest[25048:4695625] refreshPreferences: HangTracerDuration: 500
2017-11-04 19:18:30.100615-0500 watchapptest[25048:4695625] refreshPreferences: ActivationLoggingEnabled: 0 ActivationLoggingTaskedOffByDA:0
getting here A?
day#Optional(28) stand hours 14.0
day#Optional(29) stand hours 14.0
day#Optional(30) stand hours 14.0
day#Optional(31) stand hours 14.0
day#Optional(1) stand hours 16.0
day#Optional(2) stand hours 13.0
day#Optional(3) stand hours 15.0
day#Optional(4) stand hours 13.0
abc 14 count
abc 14 count
abc 14 count
abc 14 count
abc 16 count
abc 13 count
abc 15 count
abc 13 count
I am new to HealthKit, so there probably is a nicer way to do this. But this seems to work for me. I check the actually standing minutes and call the completion handler with minutes > 0.
private let store = HKHealthStore()
func askPermission() {
let standType = HKQuantityType.quantityType(forIdentifier: .appleStandTime)!
store.requestAuthorization(toShare: [], read: [standType], completion: { (success, error) in
self.didStandThisHour { (didStand) in
print("Did stand this hour: \(didStand)")
}
})
}
func didStandThisHour(_ didStand: #escaping (Bool) -> ()) {
let store = HKHealthStore()
let calendar = Calendar.autoupdatingCurrent
let dateComponents = calendar.dateComponents([.year, .month, .day, .hour], from: Date())
let endDate = Date()
let startDate = calendar.date(from: dateComponents)!
let standTime = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.appleStandTime)!
var interval = DateComponents()
interval.hour = 1
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
let query = HKStatisticsCollectionQuery(quantityType: standTime, quantitySamplePredicate: predicate, options: [.cumulativeSum], anchorDate: startDate, intervalComponents:interval)
query.initialResultsHandler = { query, results, error in
guard error == nil, let myResults = results else {
fatalError("Something is wrong with HealthKit link")
}
myResults.enumerateStatistics(from: startDate, to: endDate, with: { (statistics, stop) in
guard let quantity = statistics.sumQuantity() else {
didStand(false)
return
}
let minutes = quantity.doubleValue(for: .minute())
didStand(minutes > 0)
})
}
store.execute(query)
}
Ok, if you want to retrieve today's activity ring info (including stand hours) you first request user authorization for the object type you want to retrieve:
let healthStore = HKHealthStore()
let objectTypes: Set<HKObjectType> = [
HKObjectType.activitySummaryType()
]
healthStore.requestAuthorization(toShare: nil, read: objectTypes) { (success, error) in
// Authorization request finished, hopefully the user allowed access!
}
Then you can use this predicate to retrieve today's date:
let calendar = Calendar.autoupdatingCurrent
var dateComponents = calendar.dateComponents(
[ .year, .month, .day ],
from: Date()
)
// This line is required to make the whole thing work
dateComponents.calendar = calendar
let predicate = HKQuery.predicateForActivitySummary(with: dateComponents)
Create a query...
let query = HKActivitySummaryQuery(predicate: predicate) { (query, summaries, error) in
guard let summaries = summaries, summaries.count > 0
else {
return
}
// Handle data
}
The data you'll receive is of type HKActivitySummary and you can retrieve, for example:
let sandUnit = HKUnit.count()
let standHours = summary.appleStandHours.doubleValue(for: standUnit)
I need to query HKStatistics for average heart rate, with Swift 2.2. I've learned from research the parameter I need is HKStatisticsOptionDiscreteAverage
I have code for the workout session. How can I add the function to this code below measuring heart-rate to return the heart rate average of the workout session with HKStatisticsOptionDiscreteAverage?
func createHeartRateStreamingQuery(workoutStartDate: NSDate) -> HKQuery? {
// adding predicate will not work
// let predicate = HKQuery.predicateForSamplesWithStartDate(workoutStartDate, endDate: nil, options: HKQueryOptions.None)
guard let quantityType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate) else { return nil }
let heartRateQuery = HKAnchoredObjectQuery(type: quantityType, predicate: nil, anchor: anchor, limit: Int(HKObjectQueryNoLimit)) { (query, sampleObjects, deletedObjects, newAnchor, error) -> Void in
guard let newAnchor = newAnchor else {return}
self.anchor = newAnchor
self.updateHeartRate(sampleObjects)
}
heartRateQuery.updateHandler = {(query, samples, deleteObjects, newAnchor, error) -> Void in
self.anchor = newAnchor!
self.updateHeartRate(samples)
}
return heartRateQuery
}
func updateHeartRate(samples: [HKSample]?) {
guard let heartRateSamples = samples as? [HKQuantitySample] else {return}
dispatch_async(dispatch_get_main_queue()) {
guard let sample = heartRateSamples.first else{return}
let value = sample.quantity.doubleValueForUnit(self.heartRateUnit)
self.label.setText(String(UInt16(value)))
// retrieve source from sample
let name = sample.sourceRevision.source.name
self.updateDeviceName(name)
self.animateHeart()
}
}
func getAVGHeartRate() {
var typeHeart = HKQuantityType.quantityType(forIdentifier: .heartRate)
var startDate = Date() - 7 * 24 * 60 * 60 // start date is a week
var predicate: NSPredicate? = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: HKQueryOptions.strictEndDate)
var squery = HKStatisticsQuery(quantityType: typeHeart!, quantitySamplePredicate: predicate, options: .discreteAverage, completionHandler: {(query: HKStatisticsQuery,result: HKStatistics?, error: Error?) -> Void in
DispatchQueue.main.async(execute: {() -> Void in
var quantity: HKQuantity? = result?.averageQuantity()
var beats: Double? = quantity?.doubleValue(for: HKUnit.count().unitDivided(by: HKUnit.minute()))
print("got: \(String(format: "%.f", beats!))")
})
})
healthStore.execute(squery)
}
This is the Swift 3 version :)
this is objective-c example of getting the average heart BPM:
HKQuantityType *typeHeart =[HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionStrictStartDate];
HKStatisticsQuery *squery = [[HKStatisticsQuery alloc] initWithQuantityType:typeHeart quantitySamplePredicate:predicate options:HKStatisticsOptionDiscreteAverage completionHandler:^(HKStatisticsQuery *query, HKStatistics *result, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
HKQuantity *quantity = result.averageQuantity;
double beats = [quantity doubleValueForUnit:[[HKUnit countUnit] unitDividedByUnit:[HKUnit minuteUnit]]];
NSLog(#"got: %#", [NSString stringWithFormat:#"%.f",beats]) ;
}
);
}];
[self.healthStore executeQuery:squery];