I am working on an IOS sleep application where i need to do sleep analysis. I am using Healthkit for sleep data from where i can successfully fetch sleep analysis data using below code :
func retrieveSleepAnalysis(from startDate: Date?, to endDate: Date? , completion: #escaping ([HKCategorySample], Error?) -> Void) {
guard let sleepType = HKObjectType.categoryType(forIdentifier: .sleepAnalysis) else { return}
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
let query = HKSampleQuery(sampleType: sleepType, predicate: predicate, limit: 10000, sortDescriptors: [sortDescriptor]) { (query, result, error) in
if error != nil {
completion([], error)
return
}
if let result = result {
let samples = result.compactMap({ $0 as? HKCategorySample})
completion(samples, nil)
}
}
// finally, we execute our query
HKHealthStore().execute(query)
}
I am not able to find any healthKit code for Sleep REM cycles , Deep sleep , light sleep etc. Is it even possible to get this data from healthKit ? if Yes , How to do it? , if not with healthKit, How to do it in IOS Applications ?
You may find what you're looking for in this year's WWDC talk on "What's New In HealthKit"
Here's how you can declare a predicate for all samples:
// Predicate for all asleep samples (unspecified, core, deep, REM)
let allAsleepPredicate = HKCategoryValueSleepAnalysis.predicateForSamples(equalTo: .allAsleepValues)
And here's how you might use it to fetch all samples in a range:
let healthStore = HKHealthStore()
let sleepType = HKCategoryType(.sleepAnalysis)
let dateRangePredicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [dateRangePredicate, allAsleepPredicate])
let query = HKSampleQuery(sampleType: sleepType, predicate: predicate) { (query, result, error) in
// handle results
}
Hope that helps
Related
I can able to get my health data list from health kit. I used below code to get my today's step count :
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, _ in
guard let result = result, let sum = result.sumQuantity() else {
completion(0.0)
return
}
completion(sum.doubleValue(for: HKUnit.count()))
}
healthStore.execute(query)
}
But i have one more health data of my brother, where he invited me to see his health data in my real device. Now i was not able to read / get his health data. Is there any way to get that.
Any solution would be great ...!
You don't want a statics query if you want the step count. Try this;
let comp: DateComponents = Calendar.current.dateComponents([.year, .month], from: Date())
let startOfMonth = Calendar.current.date(from: comp)!
searchPredicate = HKQuery.predicateForSamples(withStart: startOfMonth, end: Date(), options: .strictStartDate)
let sampleQuery = HKSampleQuery(sampleType: .stepCount, predicate: searchPredicate, limit: limit, sortDescriptors: [])
{
(query, result, error) in
if error != nil
{
completion(-1)
}
self.hkSampleRecs.removeAll(keepingCapacity: true)
if result != nil
{
for r in result!
{
self.hkSampleRecs.append(r)
}
}
completion(self.hkSampleRecs.count)
}
healthStore.execute(sampleQuery)
Note that I haven't shown you the completion setup I used. I'm also storing the records in an array I defined elsewhere (hkSampleRecs). This example also gives data only for this month so far. Change the dates as you need.
I am trying to read the nutrition details from Health Kit, but getting empty array and error when I query the HealthKit.
func getNutritionDetails() {
let predicate = HKQuery.predicateForSamples(withStart: Date(), end: Date().addingTimeInterval(-1.0 * 60.0 * 60.0 * 24.0), options: .strictStartDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: true)
let query = HKSampleQuery.init(
sampleType: HKQuantityType.quantityType(forIdentifier: .dietaryFiber)!,
predicate: predicate,
limit: 0,
sortDescriptors: [sortDescriptor]) { (query, samples, error) in
DispatchQueue.main.async {
print(samples, error)
}
}
self.healthStore.execute(query)
}
It prints Optional([]) nil
Also, what if I want to read the nutritions in one single query to HealthKit?
I'm trying to get all heart rate samples from the past month, and extract the times and values from them.
So far, I've got the following method:
func getThisMonthsHeartRates() {
print("func called")
let heartRateUnit:HKUnit = HKUnit(from: "count/min")
let heartRateType:HKQuantityType = HKQuantityType.quantityType(forIdentifier: .heartRate)!
//predicate
let startDate = Date()
let endDate = Date() - 1.month
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: [])
//descriptor
let sortDescriptors = [
NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
]
let heartRateQuery = HKSampleQuery(sampleType: heartRateType,
predicate: predicate,
limit: Int(HKObjectQueryNoLimit),
sortDescriptors: sortDescriptors)
{ (query:HKSampleQuery, results:[HKSample]?, error:Error?) -> Void in
guard error == nil else { print("error"); return }
print("results")
print(results!)
for result in results! {
guard let currData:HKQuantitySample = result as? HKQuantitySample else { return }
print("Heart Rate: \(currData.quantity.doubleValue(for: heartRateUnit))")
print("quantityType: \(currData.quantityType)")
print("Start Date: \(currData.startDate)")
print("End Date: \(currData.endDate)")
print("Metadata: \(String(describing: currData.metadata))")
print("UUID: \(currData.uuid)")
print("Source: \(currData.sourceRevision)")
print("Device: \(String(describing: currData.device))")
print("---------------------------------\n")
}
} //eo-query
healthStore.execute(heartRateQuery)
}//eom
However, the results will always return an empty array, even though I've got samples on my device! Really curious as to how this can be and how to fix it. I'm at a total loss.
Thanks
Update
After logging the query before it gets executed and while it's being executed, this is what the console says:
<HKSampleQuery:0x1c4117610 inactive>
And
<HKSampleQuery:0x1c4117610 deactivated>
I have no idea what this means nor can I find anything online about it.
The problem might be that you have requested authorization to write .heartRate sample types, but not to read them as well. In this case you don't receive an error when executing the query, however the samples array will be empty.
I had the same problem because I was requesting authorization this way:
healthStore.requestAuthorization(toShare: types, read: nil) {}
Instead, you need to specify the types that you want to read even though they are already in the types set.
Hello I want to grab the latest datapoint for body mass of each day in a defined time interval
(in my case I need it for an interval of one week but only the last entry for each day.)
Actually, Using this code I can get all the entries from start X date to the end X date
let query = HKSampleQuery(sampleType: type!, predicate: predicate,
limit: 0, sortDescriptors: nil, resultsHandler: { (query, results, error) in
if let myResults = results {
for result in myResults {
let bodymass = result as! HKQuantitySample
let weight = bodymass.quantity.doubleValue(for: unit)
Print ("this is my weight value",weight )
}
}
else {
print("There was an error running the query: \(String(describing: error))")
}
This query returns any samples measuring weight consumed that fall within the time frame.
I just want to return the last entry recorded is there any way to do it with heath-kit query?
I've tried to define sort descriptor but I don’t find a way to make it work with defined time interval.
Thanks
I read this and this one
As you said you want to use a sort descriptor, just use Date.distantPast and Date() as your range, then just grab the first:
func getUserBodyMass(completion: #escaping (HKQuantitySample) -> Void) {
guard let weightSampleType = HKSampleType.quantityType(forIdentifier: .bodyMass) else {
print("Body Mass Sample Type is no longer available in HealthKit")
return
}
//1. Use HKQuery to load the most recent samples.
let mostRecentPredicate = HKQuery.predicateForSamples(withStart: Date.distantPast,
end: Date(),
options: [])
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate,
ascending: false)
let limit = 1
let sampleQuery = HKSampleQuery(sampleType: weightSampleType,
predicate: mostRecentPredicate,
limit: limit,
sortDescriptors: [sortDescriptor]) { (query, samples, error) in
//2. Always dispatch to the main thread when complete.
DispatchQueue.main.async {
guard let samples = samples,
let mostRecentSample = samples.first as? HKQuantitySample else {
print("getUserBodyMass sample is missing")
return
}
completion(mostRecentSample)
}
}
healthStore.execute(sampleQuery)
}
let endDate = NSDate()
let startDate = NSDate()
let v : Float?
let stepsCount:HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)!
let predicate:NSPredicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: .None)
let query = HKQuantitySample(sampleType: stepsCount, predicate: predicate, limit: 1, sortDescriptors: nil, resultsHandler: {
(query, results, error) in
if results == nil {
print(error)
}
v = result.first.Quantity
})
healthStore.executeQuery(query)
Cannot find an initializer for type 'HKQuantitySample' that accepts
an argument list of type '(sampleType: HKQuantityType, predicate:
NSPredicate, limit: Int, sortDescriptors: nil, resultsHandler: (_, _,
_) -> _)'
Just replace HKQuantitySample with HKSampleQuery and it will work fine.
For more Info refer THIS tutorial.
Where you can find sample code like:
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)
}
Documentation doesn't talk about any initializer like the one you are providing… Even looked in the Beta docs and didn't found anything about the one you are trying to call.
Please look here for existing HKQuantitySample initializers available :
https://developer.apple.com/library/ios/documentation/HealthKit/Reference/HKQuantitySample_Class/
See Dharmesh Kheni's answer for the correct way to create a query :).