Getting new heart rate data live from Health App? - ios

I'm trying to build an iPhone app based on the user's live heart rate data.
I was able to get the latest heart rate from the Health App but once new information is recorded the app is not updated until relaunch.
Is there a way to get heart rate data in live? Maybe with HKObserverQuery?
here's my code so far: (Who manages to pull the last heartbeat)
import Foundation
import UIKit
import HealthKit
class HealthStore {
var healthStore: HKHealthStore?
init() {
if HKHealthStore.isHealthDataAvailable(){
healthStore = HKHealthStore()
}
}
func requestAuthorization(completion: #escaping (Bool) -> Void){
let heartBeat = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
guard let healthStore = self.healthStore else {return completion(false)}
healthStore.requestAuthorization(toShare: [], read: [heartBeat]) { (success, error) in completion(success)
}
}
func latestHarteRate(){
guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
return
}
let startDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictEndDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [sortDescriptor]){(sample,result,error) in guard error == nil else{
return
}
let data = result![0] as! HKQuantitySample
let unit = HKUnit(from: "count/min")
let latestHr = data.quantity.doubleValue(for: unit)
print("Latest Hr\(latestHr) BPM")
healthStore?.execute(query)
}

You can use an HKAnchoredObjectQuery to create a query that returns an initial set of data and then updates to the data set.
Unfortunately, you can't provide a sort descriptor to the HKAnchoredObjectQuery, so you need to sort the data after you receive it if you don't want ascending order.
Here is a model object I created so that I could test in SwiftUI.
It creates an HKAnchoredQuery and sets an update handler function. The update handler converts the HealthKit results into my HeartRateEntry struct (This is so I could easily display the data in a SwiftUI list). The array is then sorted by descending date.
The update function stores the newAnchor that was received so that only changes are delivered in the future.
While testing I found that running the heart rate app on my watch, moving my test app into the background and then swapping back to it triggered the new heart rate data more quickly than just waiting for the new data to be delivered.
import Foundation
import HealthKit
struct HeartRateEntry: Hashable, Identifiable {
var heartRate: Double
var date: Date
var id = UUID()
}
class HeartHistoryModel: ObservableObject {
#Published var heartData: [HeartRateEntry] = []
var healthStore: HKHealthStore
var queryAnchor: HKQueryAnchor?
var query: HKAnchoredObjectQuery?
init() {
if HKHealthStore.isHealthDataAvailable() {
healthStore = HKHealthStore()
} else {
fatalError("Health data not available")
}
self.requestAuthorization { authorised in
if authorised {
self.setupQuery()
}
}
}
func requestAuthorization(completion: #escaping (Bool) -> Void){
let heartBeat = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
self.healthStore.requestAuthorization(toShare: [], read: [heartBeat]) { (success, error) in completion(success)
}
}
func setupQuery() {
guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
return
}
let startDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: .distantFuture, options: .strictEndDate)
self.query = HKAnchoredObjectQuery(type: sampleType, predicate: predicate, anchor: queryAnchor, limit: HKObjectQueryNoLimit, resultsHandler: self.updateHandler)
self.query!.updateHandler = self.updateHandler
healthStore.execute(self.query!)
}
func updateHandler(query: HKAnchoredObjectQuery, newSamples: [HKSample]?, deleteSamples: [HKDeletedObject]?, newAnchor: HKQueryAnchor?, error: Error?) {
if let error = error {
print("Health query error \(error)")
} else {
let unit = HKUnit(from: "count/min")
if let newSamples = newSamples as? [HKQuantitySample], !newSamples.isEmpty {
print("Received \(newSamples.count) new samples")
DispatchQueue.main.async {
var currentData = self.heartData
currentData.append(contentsOf: newSamples.map { HeartRateEntry(heartRate: $0.quantity.doubleValue(for: unit), date: $0.startDate)
})
self.heartData = currentData.sorted(by: { $0.date > $1.date })
}
}
self.queryAnchor = newAnchor
}
}
}

Related

Why are steps not being calculated in this function?

I have written a function that is supposed to get the user's steps by using HealthKit. Before I added the code that checks no data was manually added, it worked. After adding the new code (compoundPredicate) it does not calculate steps. Any ideas on what to change to make this work?
Here is the file:
import Foundation
import HealthKit
extension Date {
static func mondayAt12AM() -> Date {
return Calendar(identifier: .iso8601).date(from: Calendar(identifier: .iso8601).dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date()))!
}
}
class HealthStore {
var healthStore: HKHealthStore?
var query: HKStatisticsCollectionQuery?
init() {
if HKHealthStore.isHealthDataAvailable() {
healthStore = HKHealthStore()
}
}
func calculateSteps(completion: #escaping (HKStatisticsCollection?)-> Void) {
let stepType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
let startDate = Calendar.current.date(byAdding: .day, value: -7, to: Date())
let anchorDate = Date.mondayAt12AM()
let daily = DateComponents(day: 1)
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictStartDate)
let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates:
[.init(format: "metadata.%K == NO", HKMetadataKeyWasUserEntered), predicate]
)
query = HKStatisticsCollectionQuery(
quantityType: stepType,
quantitySamplePredicate: compoundPredicate,
options: .cumulativeSum,
anchorDate: anchorDate,
intervalComponents: daily)
query!.initialResultsHandler = { query, statisticsCollection, error in
completion(statisticsCollection)
}
if let healthStore = healthStore, let query = self.query {
healthStore.execute(query)
}
}
func requestAuthorization(completion: #escaping (Bool) -> Void) {
let stepType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
guard let healthStore = self.healthStore else { return completion(false) }
healthStore.requestAuthorization(toShare: [], read: [stepType]) { (success, error) in
completion(success)
}
}
}
I think HKMetadataKeyWasUserEntered is simply absent from many or most HealthKit samples, instead of being present with a value of NO.
Try this instead for the predicate format parameter: "metadata.%K != YES"

Return from query in swift [duplicate]

I'm trying to build an iPhone app based on the user's live heart rate data.
I was able to get the latest heart rate from the Health App but once new information is recorded the app is not updated until relaunch.
Is there a way to get heart rate data in live? Maybe with HKObserverQuery?
here's my code so far: (Who manages to pull the last heartbeat)
import Foundation
import UIKit
import HealthKit
class HealthStore {
var healthStore: HKHealthStore?
init() {
if HKHealthStore.isHealthDataAvailable(){
healthStore = HKHealthStore()
}
}
func requestAuthorization(completion: #escaping (Bool) -> Void){
let heartBeat = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
guard let healthStore = self.healthStore else {return completion(false)}
healthStore.requestAuthorization(toShare: [], read: [heartBeat]) { (success, error) in completion(success)
}
}
func latestHarteRate(){
guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
return
}
let startDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictEndDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [sortDescriptor]){(sample,result,error) in guard error == nil else{
return
}
let data = result![0] as! HKQuantitySample
let unit = HKUnit(from: "count/min")
let latestHr = data.quantity.doubleValue(for: unit)
print("Latest Hr\(latestHr) BPM")
healthStore?.execute(query)
}
You can use an HKAnchoredObjectQuery to create a query that returns an initial set of data and then updates to the data set.
Unfortunately, you can't provide a sort descriptor to the HKAnchoredObjectQuery, so you need to sort the data after you receive it if you don't want ascending order.
Here is a model object I created so that I could test in SwiftUI.
It creates an HKAnchoredQuery and sets an update handler function. The update handler converts the HealthKit results into my HeartRateEntry struct (This is so I could easily display the data in a SwiftUI list). The array is then sorted by descending date.
The update function stores the newAnchor that was received so that only changes are delivered in the future.
While testing I found that running the heart rate app on my watch, moving my test app into the background and then swapping back to it triggered the new heart rate data more quickly than just waiting for the new data to be delivered.
import Foundation
import HealthKit
struct HeartRateEntry: Hashable, Identifiable {
var heartRate: Double
var date: Date
var id = UUID()
}
class HeartHistoryModel: ObservableObject {
#Published var heartData: [HeartRateEntry] = []
var healthStore: HKHealthStore
var queryAnchor: HKQueryAnchor?
var query: HKAnchoredObjectQuery?
init() {
if HKHealthStore.isHealthDataAvailable() {
healthStore = HKHealthStore()
} else {
fatalError("Health data not available")
}
self.requestAuthorization { authorised in
if authorised {
self.setupQuery()
}
}
}
func requestAuthorization(completion: #escaping (Bool) -> Void){
let heartBeat = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
self.healthStore.requestAuthorization(toShare: [], read: [heartBeat]) { (success, error) in completion(success)
}
}
func setupQuery() {
guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
return
}
let startDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: .distantFuture, options: .strictEndDate)
self.query = HKAnchoredObjectQuery(type: sampleType, predicate: predicate, anchor: queryAnchor, limit: HKObjectQueryNoLimit, resultsHandler: self.updateHandler)
self.query!.updateHandler = self.updateHandler
healthStore.execute(self.query!)
}
func updateHandler(query: HKAnchoredObjectQuery, newSamples: [HKSample]?, deleteSamples: [HKDeletedObject]?, newAnchor: HKQueryAnchor?, error: Error?) {
if let error = error {
print("Health query error \(error)")
} else {
let unit = HKUnit(from: "count/min")
if let newSamples = newSamples as? [HKQuantitySample], !newSamples.isEmpty {
print("Received \(newSamples.count) new samples")
DispatchQueue.main.async {
var currentData = self.heartData
currentData.append(contentsOf: newSamples.map { HeartRateEntry(heartRate: $0.quantity.doubleValue(for: unit), date: $0.startDate)
})
self.heartData = currentData.sorted(by: { $0.date > $1.date })
}
}
self.queryAnchor = newAnchor
}
}
}

Cannot get today's steps to display into label

I am trying to create a label which displays today's steps from HealthKit. I have got as far as allowing HealthKit to read/write data, but I'm stuck on actually obtaining the data.
Can anyone offer any advice? Here's my code, including the label I want to display the steps:
import Foundation
import UIKit
import HealthKit
class HealthKitPage : UIViewController
{
let healthStore: HKHealthStore = HKHealthStore()
override func viewDidLoad()
{
var shareTypes = Set<HKSampleType>()
shareTypes.insert(HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!)
var readTypes = Set<HKObjectType>()
readTypes.insert(HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!)
healthStore.requestAuthorization(toShare: shareTypes, read: readTypes) { (success, error) -> Void in
if success {
print("success")
} else {
print("failure")
}
if let error = error { print(error) }
}
}
#IBOutlet weak var StepCount: UILabel!
}
You can fetch today's steps using HKStatisticsQuery. You can now in your view controller use getTodaysSteps method and set your label's text property.
Swift 3.1:
let healthStore = HKHealthStore()
func getTodaysSteps(completion: #escaping (Double) -> Void) {
let stepsQuantityType = HKQuantityType.quantityType(forIdentifier: .stepCount)!
let now = Date()
let startOfDay = Calendar.current.startOfDay(for: now)
let predicate = HKQuery.predicateForSamples(withStart: startOfDay, 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 {
log.error("Failed to fetch steps = \(error?.localizedDescription ?? "N/A")")
completion(resultCount)
return
}
if let sum = result.sumQuantity() {
resultCount = sum.doubleValue(for: HKUnit.count())
}
DispatchQueue.main.async {
completion(resultCount)
}
}
healthStore.execute(query)
}
You can call this method like this:
override func viewDidLoad() {
super.viewDidLoad()
getTodaysStepCount { [weak self] steps in
self?.StepCount.text = "\(steps)"
}
}

Display the last heartrate which is saved in Healthkit with swift

I am building an App in Swift for a IOS App. I just want to display the last saved heartrate of the Healthkit. Can someone help me here?
my Authorization request:
static func authorizeHealthKit() {
let HeartRateData: Set = [
HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!,
]
HealthStore.requestAuthorization(toShare: HeartRateData, read: HeartRateData) {_,_ in }
}
#IBAction func authorizeTapped(_ sender: AnyObject) {
HeartrateViewController.authorizeHealthKit()
}
get heart rate:
func fetchHeartRateWithCompletionHandler (_ completionHandler: #escaping (Double?, NSError?)-> ()) {
let now = Date()
let startDate = now
let endDate = now
let HeartRateSampleType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
let HeartRate = HKStatisticsQuery(quantityType: HeartRateSampleType!, quantitySamplePredicate: predicate, options: .cumulativeSum)
{ query, result, error in
if result != nil {
completionHandler(nil, error as NSError?)
return
}
var HeartRateData = 0.0
if let quantitiy = result!.sumQuantity() {
let heartRateUnit = HKUnit(from: "count/min")
HeartRateData = quantitiy.doubleValue(for: heartRateUnit)
}
completionHandler(HeartRateData, error as NSError?)
}
HeartRateTextField.text = String (describing: HeartRate)
}
but it doesn't display anything in the heart rate text field.
Are you executing the query?
Also, the query you are creating is not very efficient.
Your start date and end date are same, and predicate will not find heartRate sample in between them.
If you are looking for most recent heart rate sample, read about anchoredObjectQuery.

How to read heart rate from iOS HealthKit app using Swift?

I'm using the following Swift code.
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)
I get the following error message:
Cannot find an initializer for type 'HKStatisticsQuery' that accepts an argument list of type '(quantityType: HKSampleType, quantitySamplePredicate: NSPredicate, options: HKStatisticsOptions, (_, _, _) -> Void)'
Please advise me how to resolve this issue.
Reading data from ViewController (NOT apple watch extension)
Swift 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
Swift 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
Reading data with apple watch extension:
to execute query in apple watch, do the following:
heartRateQuery = self.createStreamingQuery()
health.executeQuery(heartRateQuery!)
don't forget the properties:
let health: HKHealthStore = HKHealthStore()
let heartRateUnit:HKUnit = HKUnit(fromString: "count/min")
let heartRateType:HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
var heartRateQuery:HKQuery?
/*The below methods has no Limit, query for heart infinitely once its the query its executed */
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
How to request authorization?
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
HKStatisticsQuery would not be my first choice for that. It is used for statistical calculations (i.e. minimum, maximum, average, sum).
You can use a simple 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)
}
Specifying types of constants and variables during an initialization is often redundant in Swift like in your case you has specified a parent HKSampleType type instead of its subclass HKQuantityType. So in your case just omit types declaration:
let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
let nowDate = NSDate()
var calendar = NSCalendar.autoupdatingCurrentCalendar()
If you use Swift 2.0 you should also utilize array like syntax in the next line:
let yearMonthDay: NSCalendarUnit = [NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day]
Try this way, moving in the completion handler seems to resolves this for me in 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]];
})
})
Note: I was seeing some compiler errors within closure, so have changed 2 lines to just ensure compilation-
var quantity : HKQuantity = result.averageQuantity();
var beats : Double = quantity.doubleValueForUnit(HKUnit.atmosphereUnit())
You should be using HKQuantityType instead of HKSampleType in your query:
let squery: HKStatisticsQuery = HKStatisticsQuery(quantityType: HKQuantityTypeIdentifierHeartRate, quantitySamplePredicate: predicate, options: HKStatisticsOptions.None) { (qurt, resul, errval) -> Void in

Resources