HealthKit for iOS8: Part 7

iOS 8 HealthKit Santiapps Marcio Valenzuela
iOS 8 HealthKit

4. CoreData for other non-health stats

You made it to the end!  Ok, so we are basically going to be adding another store to our app and reading and writing data to THAT store as well.

First let’s add a new tab and make it a UITableViewController as well.  It will have dynamically populated cells.

HealthKit for iOS8
HealthKit for iOS8

Now embed it!

HealthKit for iOS8
HealthKit for iOS8

 

Your final storyboard should look like this:

HealthKit for iOS8
HealthKit for iOS8

 

Add a new Swift class called Swimming Data and set that new UITableViewController scene to its class.  Make that class file look like this:

import Foundation

import UIKit

class SwimmingData: UITableViewController {

}

Now we must add CoreData.  To do this we need to create a CoreData stack and a xcdatamodeld file.  First thing is first, let’s add the xcdatamodeld file by New->File->CoreData->DataModel.  Name it SwimModel.  Create an entity called Swim and add the following attributes:

  • pace : Int16
  • date : Date
  • laps : Int16
  • meters : Double
  • totalTime : Double

Now with the xcdatamodeld file selected, go to Editor and select Create NSManagedObject subclass:

HealthKit for iOS8
HealthKit for iOS8

 

Make sure SwimModel is selected, click Next, make sure to select the Swim entity, click Next and you should get a Swim.swift class like this:

import Foundation
import CoreData
class Swim: NSManagedObject {

@NSManaged var date: NSDate
@NSManaged var laps: NSNumber
@NSManaged var totalTime: NSNumber
@NSManaged var meters: NSNumber
@NSManaged var pace: NSNumber
}

Perfect!  All you need now is your stack!  To do this, again create a New->File->Source->Swift File-> and name it CoreDataStack.  Now replace everything in there with this:

import CoreData

class CoreDataStack {

let context:NSManagedObjectContext
let psc:NSPersistentStoreCoordinator
let model:NSManagedObjectModel
let store:NSPersistentStore?

 

init() {

//1

let bundle = NSBundle.mainBundle()

let modelURL = bundle.URLForResource("SwimModel", withExtension:"momd")

model = NSManagedObjectModel(contentsOfURL: modelURL!)!

 

//2

psc = NSPersistentStoreCoordinator(managedObjectModel:model)

 

//3

context = NSManagedObjectContext()

context.persistentStoreCoordinator = psc

 

//4

let documentsURL = applicationDocumentsDirectory()

let storeURL = documentsURL.URLByAppendingPathComponent("SwimFit4")

 

let options = [NSMigratePersistentStoresAutomaticallyOption: true]

 

var error: NSError? = nil

store = psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options, error:&error)

 

if store == nil {

println("Error adding persistent store: \(error)")

abort()

}

}

 

func saveContext() {

var error: NSError? = nil

if context.hasChanges && !context.save(&error) {

println("Could not save: \(error), \(error?.userInfo)")

}

}

 

func applicationDocumentsDirectory() -> NSURL {

let fileManager = NSFileManager.defaultManager()

 

let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) as [NSURL]

return urls[0]

}

}

Now since this is not a CoreData tutorial, I will not go into the details, but every CoreData project needs a MOM, MOC and PSC.  That is what we initialize here.

Now we can begin writing to our MOC and PSC.  To test run it, let’s hardcode a value.  Go to the SwimmingData Class and first give it an import CoreData at the top.  Now declare a property for your stack inside your class of course:

lazy var coreDataStack = CoreDataStack()

var workouts = NSMutableArray()

We are creating a CoreDataStack instance and we are creating a mutable array.

Then give it a viewDidLoad method like this:

 

override func viewDidLoad() {

super.viewDidLoad()

//Create Sample Swim object

var description = NSEntityDescription.entityForName("Swim", inManagedObjectContext:coreDataStack.context)

var sampleSwim = Swim(entity:description!, insertIntoManagedObjectContext:coreDataStack.context)

sampleSwim.laps = 24

sampleSwim.meters = 50

sampleSwim.totalTime = 40

sampleSwim.pace = 6

sampleSwim.date = NSDate()

coreDataStack.saveContext()

 

//Add object to array

self.workouts.addObject(sampleSwim)

 

//Refresh UI

self.tableView.reloadData()

}

Now add an identifier for the cell like so:

let JournalViewControllerTableViewCellReuseIdentifier: NSString = "Cell"

as a property at the top of the class.

So of course don’t forget to set the identifier in your storyboard scene.  Finally, implement both datasource methods:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return self.workouts.count

}

override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell {

 

let cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath:indexPath!) as UITableViewCell

 

var myWorkout: Swim = self.workouts[indexPath!.row] as Swim

let dateFormatter = NSDateFormatter()

dateFormatter.dateFormat = "yyyy'-'MM'-'dd HH':'mm':'ss"

let date = dateFormatter.stringFromDate(myWorkout.date as NSDate)

println(date)

cell.textLabel.text = date

 

cell.detailTextLabel!.text = myWorkout.totalTime.stringValue

 

return cell;

}

And don’t forget to set your cell type to Right Detail in your storyboard.  If you Build & Run and switch to the newly created tab, you might get a crash saying:

Unable to load class Swim …

This is because you need to fully qualify the class name in CoreData, so select your xcdatamodeld file and with your Swim entity selected, make sure to append the Class name in the inspector on the right like so:

HealthKit for iOS8
HealthKit for iOS8

Basically you need to ensure that you append your project name to the Class name field.

Now run your app and go over to the Workouts tab and see your hardcoded workout in the tableview.

Before we move on, let’s take a few minutes to work on some details.  While this provides the info required by the user, it would be nice to polish it up a bit.  First, we should add the letters “mins” to the totalTime displayed in the cell.  Second, it would be nice to format the date a little more such that its more human readable.  So go back to your cellForRowAtIndexPath and make the following changes:

override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell {

let cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath:indexPath!) as UITableViewCell

var myWorkout: Swim = self.workouts[indexPath!.row] as Swim

var formatString = NSDateFormatter.dateFormatFromTemplate("EdMMM", options: 0, locale: NSLocale.currentLocale())

let dateFormatter = NSDateFormatter()

dateFormatter.dateFormat = formatString

let date = dateFormatter.stringFromDate(myWorkout.date as NSDate)

println(date)

cell.textLabel.text = date

cell.detailTextLabel!.text = myWorkout.totalTime.stringValue + " mins"

return cell;

}

There, now the user has a little mode detailed info of the data displayed.  We could go on and modify the cell to hold more data or even be selectable such that it would segue into a detail view controller to display all the info.

WRITING TO CORE DATA

Now all that is left to do is actually, remove that viewDidLoad code that writes to CoreData and instead, write to CoreData from our Workout view controller.  So back in WorkoutViewController, first import CoreData at the top, then add this property:

lazy var coreDataStack = CoreDataStack()

and finally, in the saveMyWorkout method, after we calculate our joules burned, or before, it doesn’t matter, add this code:

//E - Perhaps just store laps and meters per lap = total metes in some extra field within the SwimFit app to display it.

var description = NSEntityDescription.entityForName("Swim", inManagedObjectContext:coreDataStack.context)

var sampleSwim = Swim(entity:description!, insertIntoManagedObjectContext:coreDataStack.context)

var numberFormatter = NSNumberFormatter()

var nolaps:NSNumber? = numberFormatter.numberFromString(numberOfLapsValue!)

if let nolaps = nolaps {

sampleSwim.laps = Int(nolaps)

}

var nometers:NSNumber? = numberFormatter.numberFromString(metersPerLapValue!)

if let nometers = nometers {

sampleSwim.meters = Double(nometers)

}

var totime:NSNumber? = numberFormatter.numberFromString(workoutDurationValue!)

if let totime = totime {

sampleSwim.meters = Double(totime)

}

sampleSwim.pace = pace

sampleSwim.date = NSDate()

coreDataStack.saveContext()

This will save that other data, which is not HealthKit or health store data, into CoreData for later use.  Now let’s just go modify our SwimmingData view controller to make it fetch.

You already added a CoreDataStack variable to your SwimmingData view controller, so just add a fetchRequest var like this, right below the CoreDataStack var:

var coreDataStack: CoreDataStack!

var fetchRequest: NSFetchRequest!

Now in viewDidLoad add this neat code:

fetchRequest = coreDataStack.model.fetchRequestTemplateForName("FetchRequest")

This is a stored fetch request and to use it you must head over to the xcdatamodeld.file and create a new FetchRequest, leave its name as FetchRequest and now from the editor leave Swim as the selected entity to fetch from.  Now go back to SwimmingData and add this method:

//MARK - Helper methods

func fetchAndReload(){

var error: NSError?

let results = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [Swim]?

if let fetchedResults = results {

workouts = fetchedResults.copy() as NSMutableArray

} else {

println("Could not fetch \(error), \(error!.userInfo)")

}

tableView.reloadData()

}

And now call this method from viewDidLoad.  This will load your fetched data from CoreData into your tableview.

This will fetch the items in the order they were inserted, but you can also add a sort descriptor.

Add this lazy property at the top of your SwimmingData class:

lazy var dateSortDescriptor: NSSortDescriptor = {

var sd = NSSortDescriptor(key: "Swim.laps",

ascending: true) return sd
}()

Then in the viewDidLoad add this as a property of your fetchRequest:

fetchRequest.sortDescriptors =[dateSortDescriptors]

 NSFETCHEDRESULTSCONTROLLER OPTION

Alternatively you can also use NSFetchedResultsController.  NSFRC is a neat object that is created specifically for fetching and manipulating data from a CoreData query.  Its special in many respects but mainly because it works nicely with table views.  It can store information about table structure and can allow for interaction between its data and the tableview at the same time.  So add this property to the top of your class:

var fetchedResultsController : NSFetchedResultsController!

In your viewDidLoad:

//1
let fetchRequest = NSFetchRequest(entityName: "Swim")
let sortDescriptor = NSSortDescriptor(key: "totalTime", ascending: false) fetchRequest.sortDescriptors = [sortDescriptor] 
//2 fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil) 
//3 var error: NSError? = nil 
if (!fetchedResultsController.performFetch(&error)) { 
println("Error: \(error?.localizedDescription)") } 

Now replace your datasource methods with:

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultsController.sections!.count
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultsController.sections![section] as NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
}

Finally, the way you access data to populate your cell in cellForRowAtIndexPath is:

let mySwim = fetchedResultsController.objectAtIndexPath(indexPath) as Swim

cell.textLabel.text = date
cell.detailLabel.text = mySwim.totalTime.stringValue + " mins"

}

where date would be the formatted value of course.

Well it has been a long journey.  I hope you learned enough about Healthkit to feel comfortable enough to start working on your own app.

Have a good one!

HealthKit for iOS8: Part 6

iOS 8 HealthKit Santiapps Marcio Valenzuela
iOS 8 HealthKit

Here is the start of our WorkOut view controller:

import Foundation
import UIKit
import HealthKit

class WorkoutViewController: UITableViewController, UITextFieldDelegate {

@IBOutlet var numberOfLapsTextField: UITextField!
@IBOutlet var metersPerLapTextField: UITextField!
@IBOutlet var workoutDurationTextField: UITextField!
@IBOutlet var paceTextField: UITextField!
var numberOfLapsValue: NSString?
var metersPerLapValue: NSString?
var workoutDurationValue: NSString?
var userWeight: Double?
var  healthStore:HKHealthStore?
}

We import what we need, we subclass UITableViewController and add the Text Field delegate protocol.  Here I have created 4 labels for:

  • numberOfLaps
  • metersPerLap
  • workoutDuration
  • pace

These labels have an underlying variable for each.  The reason the first 3 are strings is because these are not health kit data per se.  These will be stored in CoreData.  However they really should be NSNumbers because it would be quite nice to store them and take advantage of CoreData’s ability to retrieve ordered data and statistical data in its fetches as well.

Finally we declare our health store property.

First let’s look at our lifecycle methods:

override func viewDidLoad() {

super.viewDidLoad()

self.fetchUsersWeight()

}

func textFieldShouldReturn (textField: UITextField) -> (ObjCBool) {

textField.resignFirstResponder()

if self.numberOfLapsTextField != nil && self.metersPerLapTextField != nil && self.workoutDurationTextField != nil {

}

return true;

}

In viewDidLoad we call a fetchUsersWeight method because we will need that to calculate calories burned.  Then we implement textFieldShouldReturn for each label.  Let’s take a look at that first method called:

func fetchUsersWeight() -> () {

var todayPredicate: NSPredicate = self.predicateForSamplesToday()

var weightType: HKQuantityType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)

self.healthStore?.aapl_mostRecentQuantitySampleOfType(weightType, predicate: todayPredicate, completion: { (weight, error) -> () in

if weight == nil {

NSLog("Sorry, weight is empty...")

return

}

if let someWeight = weight {

var weightUnit: HKUnit = HKUnit.poundUnit()

self.userWeight = weight!.doubleValueForUnit(weightUnit)

}

})

}

Once again we make a fetch using the same extension method and helper predicate method as before.  This exemplifies the use of extensions because we need to include the predicate method in this Workout class, not so the extension.  So go ahead and add the predicate method now:

func predicateForSamplesToday () -> (NSPredicate) {

let calendar: NSCalendar = NSCalendar.currentCalendar()

let now: NSDate = NSDate()

let startDate: NSDate = calendar.startOfDayForDate(now)

let endDate: NSDate = calendar.dateByAddingUnit(.CalendarUnitDay, value:1, toDate:startDate, options:nil)!

return HKQuery.predicateForSamplesWithStartDate(startDate, endDate:endDate, options:HKQueryOptions.StrictStartDate)

}

Ok so the user has 2 options here: Done or Cancel.  Cancel is easy:

@IBAction func cancel(sender: AnyObject) -> () {

self.navigationController?.popViewControllerAnimated(true)

}

Now let’s take a look at Done:

@IBAction func saveMyWorkout(sender: AnyObject) -> () {

//1.  Enter the values for your workout & capture

numberOfLapsValue = numberOfLapsTextField.text

metersPerLapValue = metersPerLapTextField.text

workoutDurationValue = workoutDurationTextField.text

//A - Need to fetch the user's weight in kgs from healthstore

var myWeight: Double = self.userWeight! * 0.453

//B - Need to convert time worked out into hours

//C - Need to select pace from some sort of switch

var pace: Double = (paceTextField!.text as NSString).doubleValue

//D - Throw away numberOfLaps = (numberOfLapsValue! as NSString).doubleValue & (metersPerLapValue! as NSString).doubleValue

var totalCaloriesBurnedByWorkout: Double =  ( (myWeight * pace) ) * ((workoutDurationValue! as NSString).doubleValue)/60

var totalJoulesBurnedByWorkout: Double = totalCaloriesBurnedByWorkout*4.184

//1.5 Set to EnergyVC before saving

let energyVCInstance: EnergyViewController = self.navigationController!.viewControllers[0] as EnergyViewController

energyVCInstance.activeEnergyBurnedValueLabel?.text = NSString(format:"%.2f",totalJoulesBurnedByWorkout)

energyVCInstance.activeEnergyBurned = totalJoulesBurnedByWorkout

energyVCInstance.refreshControl?.endRefreshing()

//2.  Dismiss and set values on EnergyVC such that they can be saved to the healthStore

//Save object to healthstore

// MUST DEFINE HKQUANTITY_TYPE

var quantityType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)

//MUST DEFINE HKQUANTITY

var quantity: HKQuantity = HKQuantity(unit: HKUnit.jouleUnit(), doubleValue:totalJoulesBurnedByWorkout)

//DATE & METADATA

var now: NSDate = NSDate()

var metadata: NSDictionary = ["HKMetadataKey":"Swim Session"]

//WORKOUT TYPE?

var workoutType = HKWorkoutActivityType.Swimming

//This creates the object to SAVE

var energyBurnt: HKQuantitySample = HKQuantitySample(type: quantityType, quantity:quantity, startDate:now, endDate:now, metadata:metadata)

NSLog("Before saving to the healthstore...")

self.healthStore?.saveObject(energyBurnt, withCompletion: { (success, error) in

NSLog("Saving to the healthstore...")

if (error != nil) {

NSLog("The error is: \(error)")

}

dispatch_async(dispatch_get_main_queue(), {

if success {

// This was for updating a uitableview

// Alert User

let alertController = UIAlertController(title: "Success!", message: "Data Saved", preferredStyle: UIAlertControllerStyle.Alert)

alertController.addAction(UIAlertAction(title: "Confirm", style: UIAlertActionStyle.Default, handler: {action in

println("confirm was tapped")

//dismiss this vc

self.navigationController?.popViewControllerAnimated(true)

}))

self.presentViewController(alertController, animated: true, completion: nil)

} else {

NSLog("An error occured saving your workout burn. In your app, try to handle this gracefully. The error was: %@.", error)

abort()

}

})

})

}

This time I take you step by step, once again, inside the same method so as to drive the point home.  First we take all necessary data from labels to make our calculations.  We make our calculation and populate totalJoulesBurnedByWorkout.

Then we set the properties in our EnergyViewController from here before we return.

And before returning, we save our data to the health store, creating an identifier, then a quantity, then a date, then some metadata and finally calling saveObject.  In the saveObject method we return an alertController for success and pop our Workout view controller, because remember this is a navigation stack, not a modally presented view controller.  Else we log an error.

In the final part, we will add CoreData to our project and save laps and meters data into CoreData as well.

C ya!

HealthKit for iOS8: Part 5

iOS 8 HealthKit Santiapps Marcio Valenzuela
iOS 8 HealthKit

Jumping right in, our Energy view controller class starts out like this:

import Foundation

import UIKit

import HealthKit

class EnergyViewController: UITableViewController {

var energyFormatter: NSEnergyFormatter {

var energyFormatter: NSEnergyFormatter?

var onceToken: dispatch_once_t = 0

dispatch_once(&onceToken, {

energyFormatter = NSEnergyFormatter()

energyFormatter?.unitStyle = NSFormattingUnitStyle.Long

energyFormatter?.forFoodEnergyUse = true

energyFormatter?.numberFormatter.maximumFractionDigits = 2

})

return energyFormatter!

}

// No required initWithCoder pasted in...

var  healthStore:HKHealthStore?

@IBOutlet weak var activeEnergyBurnedValueLabel: UILabel?

@IBOutlet weak var restingEnergyBurnedValueLabel: UILabel?

@IBOutlet weak var consumedEnergyValueLabel: UILabel?

@IBOutlet weak var netEnergyValueLabel: UILabel?

var activeEnergyBurned: Double = 0

var restingEnergyBurned: Double = 0

var consumedEnergy: Double = 0

var netEnergy: Double = 0

}

We take care of our imports, subclass UITableViewController, create our NSEnergyFormatter again, our health store property and then we create 4 UILabel outlets to display the values and 4 Doubles to store our energy values to be displayed.  What we are going to do here is just as important as how.  We will have 3 values which will compute a 4th one.  The 4th value is Net Energy which could be positive if we eat more or negative if we exercise more.  The other 3 are:

  • Active Energy Burned which will be populated from any workout sessions.
  • Resting Energy Burned which will be calculated automatically for us based on our profile.
  • Consumed Energy which will be input by the user in the Journal via the FoodPicker.

Ok let’s cover the view controller lifecycle methods.  viewDidLoad will be empty because instead we will use viewWillAppear:

override func viewWillAppear(animated: Bool) {

super.viewWillAppear(animated)

self.refreshControl?.addTarget(self, action:"refreshStatistics", forControlEvents:UIControlEvents.ValueChanged)

self.refreshStatistics()

NSNotificationCenter.defaultCenter().addObserver(self, selector:"refreshStatistics", name:UIApplicationDidBecomeActiveNotification, object:nil)

}

override func viewDidDisappear(animated: Bool) {

NSNotificationCenter.defaultCenter().removeObserver(self, name:UIApplicationDidBecomeActiveNotification, object:nil)

}

Here we set our refreshControl to call the refreshStatistics method.  Then we also add ourselves as observer to notifications when the application becomes active.  As always, we clean up on exit when the view disappears.

Now the method that gets called on every viewWillAppear and you’ll understand why it couldn’t be placed in the viewDidLoad:

func refreshStatistics () -> () {

self.refreshControl?.beginRefreshing()

var energyConsumedType: HKQuantityType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)

var activeEnergyBurnType: HKQuantityType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)

self.fetchSumOfSamplesTodayForType(energyConsumedType, unit:HKUnit.jouleUnit(), withCompletion: { (totalJoulesConsumed:Double, error:NSError?) -> () in

 

self.fetchSumOfSamplesTodayForType(activeEnergyBurnType, unit: HKUnit.jouleUnit(), withCompletion: { (activeEnergyBurned, error:NSError?) -> () in

self.fetchTotalBasalBurn({ (basalEnergyBurn, error) -> () in

if (basalEnergyBurn == nil) {

NSLog("An error occurred trying to compute the basal energy burn. In your app, handle this gracefully. Error: \(error)")

}

if (basalEnergyBurn != nil) {

// Update the UI with all of the fetched values.

dispatch_async(dispatch_get_main_queue(), {

self.activeEnergyBurned = activeEnergyBurned

self.activeEnergyBurnedValueLabel!.text = self.energyFormatter.stringFromJoules(self.activeEnergyBurned)

self.restingEnergyBurned = basalEnergyBurn!.doubleValueForUnit(HKUnit.jouleUnit())

self.restingEnergyBurnedValueLabel!.text = self.energyFormatter.stringFromJoules(self.restingEnergyBurned)

self.consumedEnergy = totalJoulesConsumed

self.consumedEnergyValueLabel!.text = self.energyFormatter.stringFromJoules(self.consumedEnergy)

self.netEnergy = self.consumedEnergy - self.activeEnergyBurned - self.restingEnergyBurned

self.netEnergyValueLabel!.text = self.energyFormatter.stringFromJoules(self.netEnergy)

self.refreshControl?.endRefreshing()

}) //END OF DISPATCH

}

}) //END OF self.fetchTotalBasalBurn

}) //END OF self.fetchSumOf2..

}) //END OF self.fetchSumOf1...

}

First we set our control to begin refreshing.  Next we create 2 type identifiers for DietaryEnergyConsumed and ActiveEnergyBurned.  Next we call 2 fetches, first for energyConsumedType and then for activeEnergyBurnType.  Then we throw in a basal burn calculation.  We will look at the basal or resting energy burn methods next but, just notice that if they return nil, we log an error, if its not nil, we set our labels to the values of the calculated energies.  Finally we end refreshing.

Ok so let’s look at the meaty methods.  First, the fetchSumOfSamplesTodayForType method:

func fetchSumOfSamplesTodayForType(quantityType:HKQuantityType, unit:HKUnit, withCompletion completion:((Double, NSError?) -> Void)? ) {

let predicate: NSPredicate = self.predicateForSamplesToday()

let query = HKStatisticsQuery(quantityType: quantityType, quantitySamplePredicate: predicate, options: .CumulativeSum) {query, result, error in

let sum = result?.sumQuantity()

if completion != nil {

let value: Double = sum?.doubleValueForUnit(unit) ?? 0.0    //NOTE: use 0.0 when sum is nil

completion!(value, error)

}

}

self.healthStore?.executeQuery(query)

}

Here we create a HKStatisticsQuery fetch which is a bit different from the regular HKQuery.  The reason is that we want to return the .CumulativeSum of all samples, not just the latest one.  We could fetch all samples for today but we would have to add them manually.  Since cumulative sums is quite common, HealthKit has a method for that.  The query returns a result and we set it to sum.  We then return that value in the completion handler.

Now the basal burn or resting energy burn is composed of 3 methods and an extension:

func fetchTotalBasalBurn( completion:(basalEnergyBurn: HKQuantity?, error: NSError?) -> ()?) {

var todayPredicate: NSPredicate = self.predicateForSamplesToday()

var weightType: HKQuantityType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)

var heightType: HKQuantityType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)

self.healthStore?.aapl_mostRecentQuantitySampleOfType(weightType, predicate:nil, completion: { (weight, error) -> () in

if weight == nil {

completion(basalEnergyBurn: nil, error:error)

return

}

self.healthStore?.aapl_mostRecentQuantitySampleOfType(heightType, predicate: todayPredicate, completion: { (height, error) -> () in

if height == nil {

completion(basalEnergyBurn: nil, error:error)

return

}

var innerError: NSError?    //NOTE: this var receives errors from dateOfBirthWithError or biologicalSexWithError

var dateOfBirth: NSDate? = self.healthStore?.dateOfBirthWithError(&innerError)

if dateOfBirth == nil {

completion(basalEnergyBurn: nil, error:innerError)

return

}

var biologicalSexObject: HKBiologicalSexObject? = self.healthStore?.biologicalSexWithError(&innerError)

if biologicalSexObject == nil {

completion(basalEnergyBurn: nil, error:error)

return

}

var basalEnergyBurn: HKQuantity = self.calculateBasalBurnTodayFromWeight(weight!, height:height!, dateOfBirth:dateOfBirth, biologicalSex:biologicalSexObject)!

completion(basalEnergyBurn: basalEnergyBurn, error: nil)

})

})

}

It may look daunting…oh who are we kidding, it is.  And it only gets worse!

First we create type identifiers for BodyMass and height.  We also create a predicate calling a separate method which we will see later.  Next we fetch the most recent quantity from the health store.  You will recall we did the exact same thing in the Profile view controller.  We are doing the same thing here but using a helper method thats included in an extension that others can use, not just this method.  So first we ask the health store for the weightType, if nil we return nil in the completion handler.  Next we ask for the weight and ditto with the completion handler.  Next we ask for dateOfBirth and biologicalSex.  This is the same we way asked for DOB in the Profile view controller.  But we have to return a completion handler on both calls, so we do.  Finally we set our basal burn HKQuantity to be saved to the health store by calling the calculateBasalBurnTodayFromWeight and we pass in our values for height, weight, sex and dob.  Once again we return a fully qualified completion handler this time.

So let’s take a look at the calculateBasalBurnTodayFromWeight method:

func calculateBasalBurnTodayFromWeight(weight:HKQuantity?, height:HKQuantity?, dateOfBirth:NSDate?, biologicalSex:HKBiologicalSexObject?) -> (HKQuantity?) {

// Only calculate Basal Metabolic Rate (BMR) if we have enough information about the user

if weight == nil || height == nil || dateOfBirth == nil || biologicalSex == nil {

return nil

}

var lenghtUnit: HKUnit = HKUnit(fromString: "cm")

var someHeight = height?.doubleValueForUnit(lenghtUnit)

let heightInCentimeters: Double = someHeight!

let weightInKilograms: Double = weight!.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(HKMetricPrefix.Kilo))

let now: NSDate = NSDate()

let ageComponents: NSDateComponents = NSCalendar.currentCalendar().components(.CalendarUnitYear, fromDate:dateOfBirth!, toDate:now, options:nil)

let ageInYears:Int = ageComponents.year

// BMR is calculated in kilocalories per day.

let BMR: Double = self.calculateBMRFromWeight(weightInKilograms, heightInCentimeters:heightInCentimeters, ageInYears:ageInYears, biologicalSex:(biologicalSex?.biologicalSex)!)

// Figure out how much of today has completed so we know how many kilocalories the user has burned.

let startOfToday:NSDate = NSCalendar.currentCalendar().startOfDayForDate(now)

let endOfToday:NSDate = NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitDay, value:1, toDate:startOfToday, options:nil)!

let secondsInDay: NSTimeInterval = endOfToday.timeIntervalSinceDate(startOfToday)

let percentOfDayComplete: Double = now.timeIntervalSinceDate(startOfToday) / secondsInDay

let kilocaloriesBurned: Double = BMR * percentOfDayComplete

return HKQuantity(unit: HKUnit.kilocalorieUnit(), doubleValue: kilocaloriesBurned)

}

First we make sure we have all the parameters needed to calculate basal or resting energy.  Remember, this is the energy burned by your body, just by carrying out its normal functions, breathing, metabolism etc.  No exercise is included here.

Then we create a unit for the height and format our height.  Ditto for our weight!  Next we calculate our age once again.  Finally we create a BMR variable which will be set by calling yet another method.   The BMR is Basal Metabolic Rate and it is calculated as a percentage of the day that has expired so far.  So basically you burn calories no matter what you do, unless you are dead.  In the morning your body will have burned a certain % of those calories.  As the day progresses, we burn more and so on and so forth.

This means we need to calculate how many seconds (NSTimeInterval) have passed since the beginning of the day.  This gives us a % of the day completed.  We then simply multiply that ratio by the BMR that a person with that weight, height, sex and age is supposed to have in a day and we get our result.

Finally we return an HKQuantity for the kilocalories burned according to the BMR and the % of day complete.

Here is a small method to take a break:

func predicateForSamplesToday () -> (NSPredicate) {

let calendar: NSCalendar = NSCalendar.currentCalendar()

let now: NSDate = NSDate()

let startDate: NSDate = calendar.startOfDayForDate(now)

let endDate: NSDate = calendar.dateByAddingUnit(.CalendarUnitDay, value:1, toDate:startDate, options:nil)!

return HKQuery.predicateForSamplesWithStartDate(startDate, endDate:endDate, options:HKQueryOptions.StrictStartDate)

}

What we are doing here is creating a start and end date for today instead of having to re-write that code everytime.

So how do you calculate BMR:

func calculateBMRFromWeight(weightInKilograms:Double, heightInCentimeters:Double, ageInYears:Int, biologicalSex:HKBiologicalSex) -> (Double) {

var BMR:Double

if (biologicalSex == HKBiologicalSex.Male) {

BMR = 66.0 + (13.8*weightInKilograms) + (5*heightInCentimeters) - (6.8*Double(ageInyears))

} else {

BMR = 655.0 + (9.6*weightInKilograms) + (1.8*heightInCentimeters) - (4.7*Double(ageInyears))

}

return BMR

}

It’s sex dependent and basically a simple linear formula.  Big whoop.  Ok.

Now let’s look at the meaty helper extension we saw earlier:

extension HKHealthStore {

func aapl_mostRecentQuantitySampleOfType(quantityType: HKQuantityType, predicate:NSPredicate?, completion:( (HKQuantity?, NSError?) -> () )? )  {

var timeSortDescriptor: NSSortDescriptor = NSSortDescriptor(key:HKSampleSortIdentifierEndDate, ascending:false)

var query =   HKSampleQuery(sampleType: quantityType, predicate: nil, limit: 1, sortDescriptors: [timeSortDescriptor]) { query, results, error in

if (results == nil) {

if (completion != nil) {

completion?(nil, error)

} //END OF IF 2...

return

} // END OF IF 1...

if ((completion) != nil) {

// If quantity isn't in the database, return nil in the completion block.

var resultados = results as NSArray

var quantitySample: HKQuantitySample = resultados.firstObject as HKQuantitySample

var quantity: HKQuantity = quantitySample.quantity

completion?(quantity, error)

} //END OF IF

} // HKSAMPLEQUERY

self.executeQuery(query)

} // END OF FUNCTION

} //END OF EXTENSION

We create a sort descriptor as we did in the Profile, because we want to order our results by the latest.  Then we create our simple HKQuery with whatever quantityType was passed in, the predicate, limit and sortDescriptor as well as the completion handler.  If results are nil, we set our completion handler value to nil and return.  Otherwise, we set our completion handler to whatever the most recent quantity fetched is because once again we take the firstObject from that results array.

Ok the only thing left here is to prepareForSegue:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

var workoutViewController: WorkoutViewController = segue.destinationViewController as WorkoutViewController//viewController as WorkoutViewController

workoutViewController.healthStore = self.healthStore!

}

The reason we segue is that we need to take the user to the point where he can enter the only value missing.  We already calculated the resting energy value internally based on the user’s profile data.  Then we calculated the consumed energy based on what the user picked as his or her consumed foods.  So now we need to know how much energy he burnt in his workout.

Race you there (Part 6)!