HealthKit for iOS8: Part 2

December 18, 2014 Leave a comment

So you got past the intro and learned about the health store and how we need authorization from the user in order to have read and write access to certain properties.  Now that the user trusts your app, let’s learn how to interact with the health store.

1. HKObjects and the health store

Before we get into reading and writing, let’s get to know HKObjects.  Here is the class tree:

HealthKit HKObject Hierarchy Santiapps.com

HealthKit HKObject Hierarchy

As you can see, HKObjectType inherits directly from NSObject.  You can basically have 2 types of HKObjects; HKCharacteristic and HKSample -Type.  HKCharacteristicType doesn’t change over time whereas HKSampleType does change, such as calories consumed, calories burnt, Glucose levels etc.  Let’s see some examples:

HKCharactersiticType has 3 main objects:

Biological Sex

Blood Type

Birthdate.

HKSampleType has objects like:

-HKCategoryType: discrete, finite values that can be enumerated such as sleep analysis.

-HKCorrelationType: for creating correlated objects grouped as one.

-HKQuantityType: used for creating objects that store numerical values.

-HKWorkoutType: used for creating workout objects.

-FURTHERMORE: HKSample has HKCategorySample & HKQuantitySample

For the most part you will simply fetch HKCharacteristic types from the health store of the user.  The user will have input those values through his/her Health app.  HKSample types on the other hand you will read and write constantly.  Let’s think about how we need to write data:

A. Decide on a Type Identifier

B. Create a matching HKObjectType

C. Create an HKSample

D. Call saveObject on the health store

Let’s take a look at saving data:

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

// do a bunch of UI stuff probably in the main queue

})

Ok so you might be thinking, what kinds of objects are involved here.  What is dateOfBirth or calorieSample?  Well the best way of understanding is to see an example.  Here are images representing the logic behind writing data to the store.  As mentioned earlier, you find a matching type, set it, create a sample for it and saveObject!  This is the process for a Category type:

HealthKit iOS8 HKCategory by Santiapps.com

HealthKit iOS8 HKCategory

We need to find the matching identifier for the category type in order to save a Category Sample.  Likewise for the Quantity type:

HealthKit iOS8 HKQuantity by Santiapps.com

HealthKit iOS8 HKQuantity

What this means is that before you call saveObject and pass it in that calorieSample, you need to have properly defined calorieSample:

// 1.  MUST FIND THE RIGHT TYPE FOR ENERGY BEING CONSUMED

var quantityType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)

// 2. MUST CREATE AND HKQUANTITY FOR THAT TYPE

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

// 3. MUST DEFINE A DATE FOR THE SAMPLE AND OPTIONALLY SOME METADATA 

var now: NSDate = NSDate()

var metadata: NSDictionary = [“HKMetadataKeyFoodType”:”Ham Sandwich”]

//4. CREATE HKOBJECT TO BE SAVED

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

Finally you can call the saveObject method.  That’s not so bad.  So you would do the same for energy burnt in a workout, calcium intake, etc.

Now let’s take a look at how we would read data from the store:

func fetchUsersAge () -> () {

var error: NSError?

var dateOfBirth = self.healthStore?.dateOfBirthWithError(&error)

if error != nil {

NSLog(“An error occured fetching the user’s age information. In your app, try to handle this gracefully. The error was: \(error)”)

//Present VC

abort()

}

}

As you can see, this is quite simple, we basically say self.healthStore?.dateOfBirthWithError.  Now dateOfBirth is not only a finite, or discrete measure but its also a Characteristic type, it doesn’t change with time.  How would you read other data, HKSampleTypes such as height and weight or Dietary Calories which are not discrete, in other words not whole numbers but infinitesimally scalar and change constantly?  That’s what HKQuery is for!

2. Queries & Stats

Sometimes you want to be able to query the health store for data, that’s what HKQuery is for.  If it’s a quantity sample type then we probably want to save the start and end date with it as before.  So here is an example of how to query our health store:

// 1. Create a date

var now: NSDate = NSDate()

let calendar : NSCalendar = NSCalendar.currentCalendar()

var components: NSDateComponents = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: now)

var startDate: NSDate = calendar.dateFromComponents(components)!

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

// 2. Create the identifier

var sampleType: HKSampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)

// 3. Create the predicate to search with

var predicate: NSPredicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate:endDate, options:.None)

// 4. Create the HKSampleQuery because we are querying sample types

var query: HKSampleQuery = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: 0, sortDescriptors: nil) { (query:HKSampleQuery?, results:[AnyObject]!, error:NSError!) -> Void in

if (error != nil) {

NSLog(“An error occured fetching the user’s tracked food. In your app, try to handle this gracefully. The error was: %@.”, error)

abort()

}

if results != nil {

NSLog(“Got something!”)

}

// do UI stuff probably in the main queue

self.healthStore?.executeQuery(query)     // EXECUTE QUERY

}

3. User input UI

So let’s start creating an app.  As you can see, this is all based on the sample app from Apple called Fit.  But it has been modified to add some workout data.  What we want is to be able to read data from our health store (which will provide us with a user’s profile view), collect some user info on how much energy was consumed (which will give us our Energy Consumption view) and have the user input their workout info which in our case is going to be a swimming app (this will give us a Workout view).  For the last 2 data, we will write to the health store how much energy we consumed and how much we burnt.

Ok so we have our AppDelegate and Storyboard.  To recap, you’ve activated the HealthKit capabilities in your project which if you go to the Dev Center, Xcode has created a Team provisioning profile for this app you created and its enabled for HealthKit.  This also gave you an Entitlements file in your navigator which looks like this:

HealthKit app iOS8 by Santiapps.com

HealthKit app iOS8

The Journal file is something I create to keep track of my work, ignore that.  The FoodItem is a file we will quickly throw up on the screen but is a simple Custom Class file to be used in the UI part of this app.  For the first part which deals with the Profile view controller we won’t concern ourselves with it.

Ok so let’s take a quick look at our Profile view controller class.  As always we start out with our properties:

class ProfileViewController: UITableViewController, UITextFieldDelegate {

@IBOutlet var ageValueLabel: UITextField!

@IBOutlet var ageUnitLabel: UILabel?

@IBOutlet var heightValueTextField: UITextField!

@IBOutlet var heightUnitLabel: UILabel?

@IBOutlet var weightValueTextField: UITextField!

@IBOutlet var weightUnitLabel: UILabel?

var healthStore: HKHealthStore?

}

We have created 6 IBOutlet’s.  Each UILabel will hold unit values and each corresponding UITextField will hold the respective data we fetch from the health store.

Then we create a variable for our HealthStore which, if you recall, is set for us from our AppDelegate once it receives authorization.

Now our methods:

Each time our view will appear, we want to update our data, since it may have changed:

override func viewWillAppear(animated: Bool) {

// Update the user interface based on the current user’s health information.

self.updateUsersAge()

self.updateUsersHeight()

self.updateUsersWeight()

}

Ok so with each viewWillAppear, we call methods to update our UI with the latest data from our store, which of course means we will fetch from the store and as you recall, it was different fetching a CharacteristicType such as DOB vs a Sample Type such as weight.  So let’s take a look at the simplest one first:

func updateUsersAge () -> () {

var error: NSError?

var dateOfBirth = self.healthStore?.dateOfBirthWithError(&error)

if error != nil {

NSLog(“An error occured fetching the user’s age information. In your app, try to handle this gracefully. The error was: \(error)”)

abort()

}

if dateOfBirth != nil {

NSLog(“Found a DOB \(dateOfBirth)”)

}

if dateOfBirth == nil {

var dateFormatter = NSDateFormatter()

dateFormatter.dateFormat = “yyyy-MM-dd”

dateOfBirth = dateFormatter.dateFromString(“1974-10-18″)!

}

// Compute the age of the user.

let now: NSDate = NSDate()

let calendar : NSCalendar = NSCalendar.currentCalendar()

var ageComponents = calendar.components(.CalendarUnitYear,

fromDate: dateOfBirth!,

toDate: now,

options:nil)

var usersAge: Int = ageComponents.year

var ageValueString: NSString = NSNumberFormatter.localizedStringFromNumber(usersAge, numberStyle:NSNumberFormatterStyle.NoStyle)

if let something = self.ageValueLabel!.text {

self.ageValueLabel!.text = ageValueString

}

}

Ok so first we simply fetch the value for dateOfBirth from our store and if we get an error back, we log it.  If dateOfBirth is not nil, then we log success.  You will see a strange bit now, where it checks whether if DOB is nil.  I know, we already checked if error was nil, so DOB should not be nil, but sometimes its empty.  The user may not have set DOB on his or her device yet.  This means you will get nil and your app will crash.  So in case DOB IS nil, we hard code one.  Finally we compute the user’s age based on their DOB by using NSDateComponents and we assign the computed Int to our label using NSNumberFormatter.localizedStringFromNumber method.

Now let’s see how to get height and weight, which are Sample types:

func updateUsersHeight () -> () {

// Fetch user’s default height unit in inches.

var lengthFormatter: NSLengthFormatter = NSLengthFormatter()

lengthFormatter.unitStyle = NSFormattingUnitStyle.Long

var heightFormatterUnit: NSLengthFormatterUnit = NSLengthFormatterUnit.Inch

self.heightUnitLabel!.text = lengthFormatter.unitStringFromValue(10, unit:heightFormatterUnit)

var heightType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)

self.fetchMostRecentDataOfQuantityType(heightType, withCompletion: { (mostRecentQuantity:HKQuantity?, error:NSError?) -> () in

//some code

if let something = error {

NSLog(“An error occured fetching the user’s height information. In your app, try to handle this gracefully. The error was: %@.”, something)

abort()

}

//Determine the height in the required unit.

var usersHeight: Double = 0.0

if let somethingElse = mostRecentQuantity {

var heightUnit: HKUnit = HKUnit.inchUnit()

usersHeight = mostRecentQuantity!.doubleValueForUnit(heightUnit)

// Update the user interface.

dispatch_async(dispatch_get_main_queue(), {

self.heightValueTextField.text = NSNumberFormatter.localizedStringFromNumber(usersHeight, numberStyle:.NoStyle)

})

}

})

}

Ok so we use NSLengthFormatter to determine the length style to use.  Then we use its NSLengthFormatterUnit in order to specify the unit in order to set the label for the height value.  Now we get into fetching requirements, so we must create the matching type first and then pass it into our fetch method which is called fetchMostRecentDataOfQuantityType.  So we are passing our quantity type of height, to this method.  We will study that method in a bit, but for the time being, notice we pass in a completion handler.  If that completion handler receives an error, it will log the error.  Otherwise, we create a variable for height, use the received mostRecentQuantity variable and test it since its an optional, create a heightUnit from HKUnit and unwrap the mostRecentQuantity value into our usersHeight variable using our heightUnit.

What?  Double take!  Ok, here we go, this time with weight:

func updateUsersWeight () -> (){

// Fetch the user’s default weight unit in pounds.

var massFormatter: NSMassFormatter = NSMassFormatter()

massFormatter.unitStyle = NSFormattingUnitStyle.Long

var weightFormatterUnit: NSMassFormatterUnit = NSMassFormatterUnit.Pound

self.weightUnitLabel!.text = massFormatter.unitStringFromValue(10, unit:weightFormatterUnit)

// Query to get the user’s latest weight, if it exists.

var weightType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)

self.fetchMostRecentDataOfQuantityType(weightType, withCompletion: { (mostRecentQuantity: HKQuantity?, error: NSError?) -> () in

if ((error) != nil) {

NSLog(“An error occured fetching the user’s weight information. In your app, try to handle this gracefully. The error was: %@.”, error!);

abort()

}

// Determine the weight in the required unit.

var usersWeight:Double = 0.0

if let somethingArse = mostRecentQuantity {

var weightUnit: HKUnit = HKUnit.poundUnit()

usersWeight = mostRecentQuantity!.doubleValueForUnit(weightUnit)

// Update the user interface.

dispatch_async(dispatch_get_main_queue(), {

self.weightValueTextField.text = NSNumberFormatter.localizedStringFromNumber(usersWeight, numberStyle:.NoStyle)

})

}

})

}

Again, we use NSMassFormatter for our style, its NSMassFormatterUnit for our unit, create the weight type identifier and pass it in to our fetch method along with a completion handler.  If the completion handler returns error, we log it.  Otherwise, we create a local variable to store the usersWeight, if let check mostRecentQuantity because its an optional and use it to assign its doubleValue using weightUnit to our local usersWeight variable.  Finally we update the UI in the main queue as always.

Ok so let’s take a look at this magical method, fetch something or other:

func fetchMostRecentDataOfQuantityType(quantityType: HKQuantityType, withCompletion completion: ((mostRecentQuantity:HKQuantity?, error:NSError?) -> ())? ) {

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

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

if completion != nil && error != nil {

completion!(mostRecentQuantity: nil, error: error)

return;

}

let resultsArray = results as NSArray?

var quantitySample: HKQuantitySample? = resultsArray?.firstObject as HKQuantitySample?

var quantity: HKQuantity? = quantitySample?.quantity

if completion != nil {

completion!(mostRecentQuantity: quantity, error: error)

}

}

self.healthStore?.executeQuery(query)

}

Ok, not that complicated really.  We create a NSSortDescriptor in order to arrange our results and be able to get the latest one.  We create the HKQuery and pass it in the sampleType (height or weight, depending on what was passed into the fetch method), limit results to 1 and no predicate.  We pass in the sort descriptor and another completion handler.  Here are the cases tested next:

- If the HKQuery completion handler is NOT nil && the error is also NOT nil, then there is an error, so return the other completion handler with nil

- Otherwise, take the results AnyObject from the HKQuery and cast it as NSArray, get its firstObject as HKQuantitySample, get its quantity and set it to some local variable called quantity.  Then again check if the original completion is NOT nil, then return the original completion handler with the quantity results.  Finally execute the query!

Finally, you may have noticed the user can update their height and weight.  And we adopted the UITextFieldDelegate protocol for that.  So let’s:

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

textField.resignFirstResponder()

if textField == self.heightValueTextField {

self.saveHeightIntoHealthStore()

} else if textField == self.weightValueTextField {

self.saveWeightIntoHealthStore()

}

return true;

}

call save each time the user modifies their height or weight.  And those methods are simply:

func saveHeightIntoHealthStore () -> () {

var formatter: NSNumberFormatter = self.numberFormatter()

var height: NSNumber?

if let somethingA = self.heightValueTextField!.text {

height = formatter.numberFromString(self.heightValueTextField!.text)

}

let cosa:NSNumber = 8

var otra = cosa.doubleValue

if height == height {

// Save the user’s height into HealthKit.

var heightType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)

var heightQuantity: HKQuantity = HKQuantity(unit:HKUnit.inchUnit(), doubleValue: height!.doubleValue)

var heightSample: HKQuantitySample = HKQuantitySample(type: heightType, quantity:heightQuantity, startDate:NSDate(), endDate:NSDate())

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

if (!success) {

NSLog(“An error occured saving the height sample %@. In your app, try to handle this gracefully. The error was: %@.”, heightSample, error)

abort()

}

})

}

}

Format the value, carefully unwrap the textfield value, create a new height type identifier, height quantity and height sample and save it to the health store.  Likewise for the weight:

func saveWeightIntoHealthStore () -> () {

var formatter: NSNumberFormatter = self.numberFormatter()

var weight: NSNumber?

if let somethingIsInsideOf = self.weightValueTextField!.text {

weight = formatter.numberFromString(self.weightValueTextField!.text)!

NSLog(“The weight entered is not numeric. In your app, try to handle this gracefully.”);

abort()

}

if weight == weight {

// Save the user’s weight into HealthKit.

var weightType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)

var weightQuantity: HKQuantity = HKQuantity(unit: HKUnit.inchUnit(), doubleValue: weight!.doubleValue)

var weightSample: HKQuantitySample  = HKQuantitySample(type:weightType, quantity:weightQuantity, startDate:NSDate(), endDate:NSDate())

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

if (!success) {

NSLog(“An error occured saving the weight sample %@. In your app, try to handle this gracefully. The error was: %@.”, weightSample, error)

abort()

}

})

}

}

And we need the number formatter method:

func numberFormatter ()->(NSNumberFormatter) {

var numberFormatter: NSNumberFormatter?

dispatch_once(&onceToken, {

numberFormatter = NSNumberFormatter()

})

return numberFormatter!

}

Since we use this onceToken, we need to define it globally at the top of the class by adding this line below the following imports:

import UIKit

import HealthKit

var onceToken: dispatch_once_t = 0

See you in Part 3!

Categories: Iphone Developer

HealthKit for iOS8: Part 1

December 10, 2014 Leave a comment
HealthKit iOS8 by Santiapps.com

HealthKit iOS8

Intro: What it’s for?  

HealthKit is a framework that allows you to store health data to a persistent store on the users device.  We will begin with an app from Part 1 but we will take some detours that are important to understand so bare with me.

The first steps are:

- Create a tab bar application in Swift for iPhone Only

- Rename First and Second view controllers to Profile and Journal and make them UITableViewControllers

- In Capabilities turn on HealthKit

HealthKit, (HK), requires permissions to access the health store since most of this data is considered confidential.  So to do this, move over to the AppDelegate.swift.  Add this to appDidFinishLaunching method in AppDelegate:

if (HKHealthStore.isHealthDataAvailable() == true) {

self.healthStore = HKHealthStore() //needs to be var for it to work?

var writeDataTypes = self.dataTypesToWrite()

var readDataTypes = self.dataTypesToRead()

self.healthStore!.requestAuthorizationToShareTypes(writeDataTypes, readTypes: readDataTypes, completion: { (success, error) -> Void in

NSLog(“success \(error)”)

if (!success) {

NSLog(“You didn’t allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: %@. If you’re using a simulator, try it on a device.”, error)

//Present VC

return

} else {

NSLog(“success authorizing the healthstore!”)

NSLog(“writeDataTypes is%@”,writeDataTypes)

NSLog(“readDataTypes is%@”,readDataTypes)

}

// Handle success in your app here.

self.setupHealthStoreForTabBarControllers()

})

}

This requests permission from the user’s health store (on their device) in order to read and write personal data.  The user will be prompted to authorize whatever data he or she feels comfortable with.

Those NSSets containing the user data to read and write are created like so:

func dataTypesToWrite () -> (NSSet) {

var dietaryCalorieEnergyType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)

var activeEnergyBurnType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)

var heightType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)

var weightType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)

var aSet: NSSet = NSSet(objects: dietaryCalorieEnergyType, activeEnergyBurnType, heightType, weightType)

return aSet

}

We do something a little different in the read types:

func dataTypesToRead () -> NSSet {

let values = [HKQuantityTypeIdentifierDietaryEnergyConsumed,

HKQuantityTypeIdentifierActiveEnergyBurned,

HKQuantityTypeIdentifierHeight,

HKQuantityTypeIdentifierBodyMass,

HKCharacteristicTypeIdentifierDateOfBirth,

HKCharacteristicTypeIdentifierBiologicalSex]

return values.reduce(NSMutableSet()) { (var theSet, let identifier) in

if identifier != nil {

if let something = HKCharacteristicType.characteristicTypeForIdentifier(identifier) {

theSet.addObject(something)

} else if let quantity = HKQuantityType.quantityTypeForIdentifier(identifier) {

theSet.addObject(quantity)

}

}

return theSet

}

}

And finally, since we are going to be using the health store to read and write from many view controllers so we need to propagate our central health store throughout those view controllers.  So we need to use this method:

func setupHealthStoreForTabBarControllers () -> () {

var tabBarController = self.window!.rootViewController as UITabBarController

for navigationController: UINavigationController in tabBarController.viewControllers as Array {

var viewController = navigationController.topViewController

if viewController.isKindOfClass(ProfileViewController) {

var profileViewController: ProfileViewController = viewController as ProfileViewController

profileViewController.healthStore = self.healthStore!

} else if viewController.isKindOfClass(JournalViewController) {

var journalViewController: JournalViewController = viewController as JournalViewController

journalViewController.healthStore = self.healthStore!

} else if viewController.isKindOfClass(EnergyViewController) {

var energyViewController: EnergyViewController = viewController as EnergyViewController

energyViewController.healthStore = self.healthStore!

}

}

}

Now our app has access to our health store.  So recapping what we’ve done in this intro part, we basically requested permission from the health store, specified the data types to read and write and finally propagated our fully authorized health store to our child view controllers.

This is what our storyboard will look like:

Storyboard for HealtKit App Santiapps.com

Storyboard for HealthKit App

 

Here we start out with a tab bar controller with 3 UITableViewControllers as children.  The best way to do this is to drag UITableViewControllers from the Object Library in case you removed the original First and Second placeholder view controllers supplied by the template.  But you could also just drag a tableview and a cell into each of those 2 supplied view controllers and drag an additional one into the storyboard, its up to you.  Then select each of the 3, one by one, and in Editor -> Embed in Navigation Controller.

Here is the ProfileViewController:

HealthKit iOS8 App by Santiapps.com

HealthKit iOS8 App – Profile

As you can see, these are not prototype-dynamic cells but rather custom static cells.  In this case we have given the UINavBar a title and we have divided up the tableview into 3 sections: one for the users age, another for the users height and the last one for the users weight.  You can do this by setting the Sections property of the tableview in the Attributes Inspector, setting the style to Grouped and giving each section a name.

The Journal view controller is the only one that has prototype cells actually.  It looks like this:

HealthKit App iOS8 by Santiapps.com

HealthKit App iOS8 – Journal

 

Here we will simply create a tableview with dynamically populated data from a hardcoded array.  The type of cell is Detail Style and we add a button on the top right.  The idea here is that the user can select items from a list that provide a certain number of calories or joules as input.  Remember, this is the Energy Consumption tab where the user can specify his daily intake.  So of course the “Add” button calls a view controller where the user can select from a list of items:

HealthKit app iOS8 by Santiapps.com

HealthKit app iOS8 – FoodPicker

 

Ok so this one also has dynamic cells, this is the tableview that will actually be filled with the hardcoded items.  Once the user selects an item, it will be passed back to the Journal view controller.  This is the FoodPicker view controller.

Finally here is the EnergyViewController which will basically unify all data:

HealthKit app iOS8 by Santiapps.com

HealthKit app iOS8

Wait!  What do you mean all the data, so far we only have the profile data read from the health store and consumed data, what about the workout?  Well that comes in the next view controller but for now, suffice it to say that this is a static table view cell with data fed in by:
Active Energy Burned = what you burn exercising

Resting Basal Burn = what you burn just breathing

Consumed Energy = what you ate

Net Energy = your final tally for the day

 

You input the Active Energy from the Workout view controller called when you tap the “Add” button in the Energy view controller which looks like this:

HealthKit app iOS8 by Santiapps.com

HealthKit app iOS8

 

Notice something important here, we are capturing workout specific data such as laps, time, meters and pace.  This is not health data per se.  And that is precisely what HealthStore was NOT made for.  Its important to make this distinction because if you open your Health app you will not find laps, meters, km biked, tennis sets played.  That is workout-specific data and the only specific data Health app records, is Steps, because its something the iPhone can record by itself.  The Health app and the health store was conceived to record health data and it can’t very well cover all sport-specific needs.  However all that workout-specific data, laps swam, km biked or sets played, translates, somehow, into calories burned.  Now THAT is a point of convergence for all workouts and that is the kind of thing stored by the health store.  Take a look at your Health app and you will see a Health Data icon which lets you see the kinds of data the app stores.

So why is this important, well, as you will see, we will be storing energy in and energy out.  But we are still capturing laps and meters and time from the user and of course that IS important to the user.  He or she will still want to see their progress in terms of laps and time.  So we will need to incorporate CoreData in the end, in order to store that kind of data.

Ok in the next part we will look at the core of health data in iOS, HKObjects and how to use them!

 

Categories: Iphone Developer

Swift Closures Quick Reference: Part 3

November 8, 2014 Leave a comment

Now let’s write our own closure!

func fetchMostRecentDataOfQuantityType(quantityType: HKQuantityType, withCompletion completion: ((mostRecentQuantity:HKQuantity?, error:NSError?) -> ())? ) {

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

[timeSortDescriptor], resultsHandler: { (query:HKSampleQuery!, results:[AnyObject]!, error:NSError?) -> Void in

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

if completion != nil && error != nil {

completion!(mostRecentQuantity: nil, error: error)

return;

}

let resultsArray = results as NSArray?

var quantitySample: HKQuantitySample? = resultsArray?.firstObject as HKQuantitySample?

var quantity: HKQuantity? = quantitySample?.quantity

if completion != nil {

completion!(mostRecentQuantity: quantity, error: error)

}

}

self.healthStore?.executeQuery(query)

}

Notice we declare a function that takes a quantityType parameter and a completion parameter.  The completion parameter is a closure (it also has an internal and external name).  The closure is defined as:

{ (mostRecentQuantity, error) -> () } // which takes 2 parameters itself and returns void *dont worry about the ?

Internally, the function uses the completion block.  Whenever we wish to call the completion block, we test for it and say completion (mostRecentQuantity, error) which sets the completion block.  Again don’t worry about the ?

Now let’s actually use that function in code.  We call it with self and pass it in heightType as the quantityType parameter and pass it the values for mostRecentQuantity and any error and the code to be executed.  That code takes the error and checks if there is any in order to log it.  Otherwise, it takes mostRecentQuantity and uses it to set a local variable.

self.fetchMostRecentDataOfQuantityType(heightType, withCompletion: { (mostRecentQuantity:HKQuantity?, error:NSError?) -> () in

if let something = error {

NSLog(“An error occured fetching the user’s height information. In your app, try to handle this gracefully. The error was: %@.”, something)

abort()

}

//Determine the height in the required unit.

var usersHeight: Double = 0.0

if let somethingElse = mostRecentQuantity {

var heightUnit: HKUnit = HKUnit.inchUnit()

usersHeight = mostRecentQuantity!.doubleValueForUnit(heightUnit)

// Update the user interface.

dispatch_async(dispatch_get_main_queue(), {

self.heightValueTextField.text = NSNumberFormatter.localizedStringFromNumber(usersHeight, numberStyle:.NoStyle)

})

}

})

Here is another example of one we can write.  I actually borrowed this from a web tutorial and a GitHub post:

func searchUsersWithSearchTerm(searchTerm: String, completionClosure: (users :User[]) ->()) {
      var request = NSMutableURLRequest(URL: NSURL(string: "https://api.github.com/search/users?q=\(searchTerm)"))
      request.HTTPMethod = "GET"
      let postDataTask = self.urlSession.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
           if error {
                println(error.localizedDescription)
           }
           println(response)
           var repoJSON : NSMutableDictionary = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: nil) as NSMutableDictionary
           var jsonArray = repoJSON["items"] as NSMutableArray
           var users : User[] = User().parseJSONIntoUsers(jsonArray)
           println(users.count)
           completionClosure(users: users)
      })
      postDataTask.resume()
 }

The function takes a searchTerm parameter and a completionClosure much like the previous one.  That closure is:

{ (user:[User]) -> ( )  } // takes a User array named user and returns void.

The function performs some heavy-slow work and then ends up populating an array of Users.  Once we have our data, we want to call our completion block.  So normally you would use a parameter inside a function to do something.  Here we are using our closure parameter to do something, call it!  We call it by saying closure(parameters) as if we were calling a function().  To call a function you pass in the parameters that function requires.  To call a closure you call the parameters that closure requires.  In this case, our closure only requires one parameter, the users array.  So basically the code inside the function will be executed serially and only after the data is returned from the fetch, will the completion closure be called.  Once its called, then it will do whatever was passed into it inside { }.

Now how would we call this function:

self.someController.searchUsers("Woz") { (users: User[]) in
    self.searchUsers = users
    NSOperationQueue.mainQueue().addOperationWithBlock() { () in
        self.collectionView.reloadData()
    }
}

We call the function by passing it the two parameters it requires (searchTerm and completion closure).  Normally we would say (param1,param2), but when the last parameter of a function is a closure, we are allowed to tag it as:

function(param1) { //closure code }

In short, when you call a function that has a completion closure as a parameter you pass it the parameters it needs to execute it’s own code and the closure to execute afterwards.  It first executes it’s own code (which in our case got data from the web) and then that same code is in charge of calling a completion closure only after it’s done with it’s own code.  By calling completion(), the function is calling the completion closure which contains the code we passed it.

How to properly use pre-made closures:

1. var = method(param1, param2, param3) handler4{ params in //if code } //handler4 is optional
        OR
2. var = method(param1, param2, param3, handler:{() -> Void in //if code })

Hope you enjoyed this.

Categories: Iphone Developer

Swift Closures Quick Reference: Part 2

October 24, 2014 Leave a comment

Let’s analyze some useful applications of closures in everyday code!

Ok so let’s take a look at a real life function that uses a closure.  A typical closure is a completion handler.  A completion handler is a parameter, just like any other, that is passed into a function as a closure.  When that code gets executed, the completion handler gets filled.  Then your function will use the value of that completion handler to do something useful.

Here are some typical uses of closures in API’s.  The typical one is UIView.animateWithDuration.  Open Xcode and start writing UIView.anim… and it will autocomplete for you with this:

UIView.animateWithDuration(<duration: NSTimeInterval>, animations: <() -> Void() -> Void>)

This is telling you that the animateWithDuration takes 2 parameters:

duration which is an NSInterval type called duration &

animations which is a closure type which takes void parameters and returns void.  Remember, animations is just another variable we are passing in, so its separated with a comma from duration.

If you hit enter over the duration parameter, you can write in whatever you want.  If you then tab, it moves over to the ()->Void parameter.  Hit enter again.  The closure turns into this format:

{ () -> Void in

<#code#>

}

Where the { } define your closure and you can see the closure takes () and returns -> () as well.  Except that in this case the final () after -> are replaced by the keyword Void.  Then we get our keyword to transition from the ending ->() in a function to our actual function or closure code which will be enclosed in { }.

In the end you might end up with something like this:

UIView.animateWithDuration(1,

animations: {() in redBox.alpha = 0 },

completion:{(Bool) in println(“red box has faded out”) })

which is interpreted as:

The function animateWithDuration says: “The value for the duration parameter is 1 second.  The value for animation is a closure of block of code enclosed by { }.  Finally the value for completion is also a closure enclosed by a second { }.”

The animation closure says: “I take no parameters and return void and my code is = in = change the redBox’s alpha to 0.

The completion closure says: “I takes a Bool parameter and returns void and my code is = in = print the message.”

So we are passing those 2 blocks of code to be executed into the function as parameters.

It basically translates to this:

UIView.animateWithDuration(duration: NSTimeInterval,

animations: (() -> Void)?,

completion: ((Bool) -> Void)?)

Where are you can see, 3 parameters out of which 2 are closures.  Both closures return void but the second one takes a Bool.

So what does it mean?  Well, it says:

1. Here is how much the duration is going to last

2. Here is the animation you will perform inside of the { }.  That requires no parameters and returns nothing.

3. Oh and btw, here is another block of code { } but take a Bool and only execute { } if the Bool is true.  The Bool is set to true when the animation passed in has already finished.

Let’s take a quick look at some closures you’ll find in Apple API’s:

1.  This passes in the dispatch queue as parameter 1 and a closure to downloadData as parameter 2.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {

self.downloadDataForRegisteredObjects(true, toDelete:false)

})

2.  This function called performBlockAndWiat passes in a closure without parameters and with Void and the code to be executed PLUS another function called executeFetchRequest.

CoreDataController.sharedDataController.backgroundManagedObjectContext?.performBlockAndWait({ () -> Void in

var error:NSError?

var results:NSArray

CoreDataController.sharedDataController.backgroundManagedObjectContext?.executeFetchRequest(request, error:&error)

if ((results.lastObject) != nil)   {

date = (results.lastObject as NSArray).valueForKey(“updatedAt”) as? NSDate

}

}) 

3.  This assigns a function return to a variable.  That function is GET() and it receives a className parameter, a parameters parameter and a success completion block parameter.  That success completion block parameter is a closure that takes an operation and a response and returns void.  It is called when the operation was successful and writes the operation’s response to disk. If the operation fails, it logs the error.

var operation: AFHTTPRequestOperation = self.GET(“classes/\(className)”, parameters: parameters, success: { (operation, response) -> Void in

// success code…

if response.isKindOfClass(NSDictionary) {

self.writeJSONResponse(response, className:className as NSString)

}

}, failure: { (operation, error) -> Void in

// failure code…

NSLog(“Request for class %@ failed with error: \(className), \(error)”)

}) 

4.  This assigns the function result to a variable as well.  It calls the batchOfRequestOperations method and passes it an operationsArray and a progressBlock and a completion block but in this case you can’t see the “completion” name of that last parameter.  Sometimes when you start writing out a function name and it takes a closure as a parameter and its the last one, you don’t have to name it? Why?

var batchOperations: NSArray = AFURLConnectionOperation.batchOfRequestOperations(operationsArray,

          progressBlock: { (finishedOps:UInt, totalOps:UInt) -> Void in

                    NSLog(“%lu of %lu complete”, finishedOps, totalOps)

})  { (op) -> Void in

                    if (!toDelete) {

                              self.processJSONDataRecordsIntoCoreData()

                    } else {

                             self.processJSONDataRecordsForDeletion()

                   }

}

I guess its because it’s the last parameter in the method call.

Next we take a look at writing our own closures.

Categories: Iphone Developer

Swift Closures Quick Reference: Part 1

October 18, 2014 Leave a comment

Blocks/Closures are confusing!  They’re confusing because its a bit abstract.  Most tutorials cover how a block is declared and used.

Sometimes blocks or closures can me even more confusing…

A block is a bunch of code wrapped up in a {}.

You can 2 either of 2 things with them:

A.  You can assign that block of code to a variable. (this is where completionHandlers, also a confusing concept, fit in)

B.  You can use that block of code directly

Let’s take a look at assigning it to something.  No doubt you have seen a construct like:

var someName = “Mars”

or

var hisAge = 39

This would be considered hardcoding that value to the variable.

Now surely you have seen a function that does something more practical such as calculate or do something in order to return a value.  In the case of someName, well, we could fetch it from a list of users in a web service database.  In the case of hisAge we could calculate it.  Either process would occur in a function.  So we could instead of hardcoding a value, say:

var someName = getHisName()

or

var hisAge = getHisAge()

Well what we are doing here is actually ‘passing a block of code’ to a variable already.  Sorta.  We could somehow imagine that:

var hisAge = getHisAge() { //all the code inside getHisAge function }

which translates to:

var hisAge = { //all the code inside getHisAge function }

Ok, so that’s more or less what a block or closure is.

Where it gets weird, or complicated but just because of the way it looks is when they are passed to functions. You could go ahead and say something like:

func thisIsSomeFunction () -> () { //code }

which is a function that doesn’t take parameters and returns nothing.  Let’s give it a parameter:

func thisIsSomeFunction (aParameter:pType) -> () { //code }

This takes aParameter of pType.  Now replace that parameter with hisAge:

func thisIsSomeFunction (hisAge) -> () { //code}

Now let’s replace hisAge for what it stands for (which is { //all the code inside getHisAge function } )

func thisIsSomeFunction (  () -> () ) -> () { //code}

where () -> () stands for whatever hisAge is equal to, which is the getHisAge function…

Of course the getHisAge function must at least return something, an age, which would typically be an Int:

func thisIsSomeFunction (  () -> (Int) ) -> () { //code }

It would be wise to calculate someone’s age using at least his date of birth, so:

func thisIsSomeFunction (  (NSDate) -> (Int) ) -> () { //code }

Ok so our getHisAge function is in blue and it is passed into this new function.  Now it would be nice to pass in the original getHisAge code which would fit somewhere in here:

func thisIsSomeFunction (  (NSDate) -> (Int) {//getHisAge code} ) -> () { //code }

So for this purpose we have the keyword “in”:

func thisIsSomeFunction (  (NSDate) -> (Int) in {//getHisAge code} ) -> () { //code }

Hope you enjoyed it.  See you in the next part!

Categories: Iphone Developer

Swift is Confusing: Classes, Structures, Designated Initializers, Instance Methods, Type Methods, Functions, Methods, Convenience Initializers & External Parameter Names

October 10, 2014 Leave a comment
Swift is Confusing: Classes, Structures, Designated Initializers, Instance Methods, Type Methods, Functions, Methods, Convenience Initializers & External Parameter Names

Swift is Confusing

Class vs Structs

Both: Store values, initialize, subscripts, extensible & protocol

Class can inherit, de-initialize, reference counting & typecast

Functions vs Methods

Methods are FUNCTIONS INSIDE A CLASS

Functions can be inside or OUTSIDE A CLASS!

Cannot use functionName(param1,param2) to call a function declared inside a class {}

Methods:

  1. It is implicitly passed the object for which it was called
  2. It is able to operate on data that is contained within the class

Instance Methods vs Type Methods (Instance Method vs Class Methods I think)

Methods are functions that are associated with a particular type. Classes, structures, and enumerations can all define instance methods, which encapsulate specific tasks and functionality for working with an instance of a given type. Classes, structures, and enumerations can also define type methods, which are associated with the type itself. Type methods are similar to class methods in Objective-C.

  • class Counter {
  • var count = 0
  • func increment() {
  • count++
  • }
  • }
  • let counter = Counter()
  • counter.increment()

vs

  • class SomeClass {
  • class func someTypeMethod() {
  • // type method implementation goes here
  • }
  • }
  • SomeClass.someTypeMethod()

Class Factory vs Initializer

This is not particular to Swift but may come up in searches.  A Class Factory method is what was know in ObjC as factory methods and I even saw them references as convenience methods or constructors.  These are instead of:

NSArray *someArray = [[NSArray alloc] init]];

they would be:

NSArray *someArray = [NSArray arrayWithObjects:@”One”, @”Two”];

Another example:

  • UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
  • let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)

ObjC class or factory methods get mapped as convenience initializers in Swift.  So:

  • UIColor *color = [UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0];

gets translated into this:

  • let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)

Designated Initializer vs Convenience Initializer

A designated initializer calls its superclass’ init and defines all values added by the self class.  Unless explicitly provided, a class inherits a super initializer from its superclass.

Any other convenience initializer calls self.init and have the convenience keyword before the init keyword.

Initialization must be done in order; own properties, super, super properties.

Initializers & Optionals in one :-)

  • class SurveyQuestion {
  • let text: String
  • var response: String?
  • init(text: String) {
  • self.text = text
  • }
  • func ask() {
  • println(text)
  • }
  • }
  • let beetsQuestion = SurveyQuestion(text: "How about beets?")
  • beetsQuestion.ask()
  • // prints "How about beets?"
  • beetsQuestion.response = "I also like beets. (But not with cheese.)"

Default Initializers

  • class ShoppingListItem {
  • var name: String?
  • var quantity = 1
  • var purchased = false
  • }
  • var item = ShoppingListItem()

All non-optional values are supplied with a default value and it is a Base Class (because it doesn’t have a super class)

Diagram:

class A {
    var x: Int
    convenience init() {
        self.init(x: 0)
    }
    init(x: Int) {
        self.x = x
    }
}

where init(x:Int) is the designated initializer and any other must have the convenience keyword.

class B: A {
    var y: Int
    convenience init() {
        self.init(y: 0)
    }
    convenience init(y: Int) {
        self.init(x: 0, y: y)
    }
    init(x: Int, y: Int) {
        self.y = y
        super.init(x: x)
    }
}

Parameter Names / Externals / The first

//Default: First Parameter is the local parameter (don't need to specify it), the rest are external parameters
    func greet (name: String, day: String) -> String {
        return "Hello \(name), today is \(day)."
    }
greet("John", day:"Monday")
    //Use Hash symbol to make the First parameter as external parameter
    func greet2 (#name: String, day: String) -> String {
        return "Hello \(name), today is \(day)."
    }
greet(name:"John", day:"Monday")

Swift Optionals Quick Reference

September 19, 2014 Leave a comment
Swift Optionals Quick Reference for Newbies by Santiapps.com

Swift Optionals Quick Reference for Newbies by Santiapps.com

Optionals confuse me so I wrote this post and hope it can be of some help.

OPTIONALS

Takeaway #1: Optionals are used to declare a variable but are not assigned a value at start

Takeaway #2: Optionals contain a Some or None value, they DONT contain a String or Array or whatever else.

Takeaway #3: Therefore we MUST unwrap the value of an Optional to see what the prize is :-) In other words, to access its value!

Takeaway #4: DECLARATION OPTIONS

A) Using the following syntax: var someVar? – You will mostly use this…

B) Using “var someVar!” <Implicitly unwrapped> – Unfortunately UIKit & other Apple frameworks will use a lot of these…

… NEED TO EXPLORE THE DIFFERENCE BETWEEN ? and ! declarations…

Turns out you can declare a variable as an implicitly unwrapped optional if you know it will, at some point, be non-nil.  So for example, in this SO post (http://stackoverflow.com/questions/24006975/why-create-implicitly-unwrapped-optionals) they talk about have viewDidLoad in a view controller call a setter upon load:

var screenSize: CGSize?

override func viewDidLoad() {

super.viewDidLoad()

screenSize = view.frame.size

}

We know that screenSize will be filled because viewDidLoad WILL be called.  Then later we do:

@IBAction printSize(sender: UIButton) {

println(“Screen size is: \(screenSize!)”)

}

We know screenSize will have a value if its ever called.  So we can instead declare it as an implicitly unwrapped optional with a ! instead of a ? in the initial var declaration.  But don’t sweat this so much right now.

Takeaway #5: ACCESS (UNWRAPPING) OPTIONS 

Takeaway #6: Method 1: Traditional (Risky): if var != nil and then access it inside the if block.

if yourOptionalTypeOrOptionalReturningFunction != nil {

doSomethingWith(tempOptional!) || setSomeValue = tempOptional!

}

But to access it you have to unwrap the present :-)  To do this you use the bang operator !  Whenever you use the ! you are ‘force unwrapping’ a variable, which means it will open it no matter what.  If nil is in there…KABOOM!  Bye bye Moose & Squirrel!  So you better have checked before hand.

Takeaway #7: Method 2: Optional Binding (aka:”if-let nil check”) (Safer): This means you use:

if let tempOptional = yourOptionalTypeOrOptionalReturningFunction {

doSomethingWith(tempOptional) || setSomeValue = tempOptional

}

This is more safe because it checks first or peeks in the box so to speak.  Thus you can use the variable without unwrapping.

< If you remove default value from a ? and have a ! to access it in code, your code will fail if-check will go to else.>

Takeaway #7: Method 3: Implicitly Unwrap: Uses ! operator (assumes var contains some value). But remember from Method 1, if nil, KABOOM!!!!!!

<If you remove default value from a ? and have a ! to access it in code, you get runtime crash = error = “can’t unwrap optional.None”>

Takeaway #8: Optionals unwrapped using? – This one is still kinda confusing to me. Has to do with optional chaining and inline downcast syntax I believe.  It means that when you have many optionals.  Let’s assume you have a class with 2 optional variables, name? and price?  Let’s pretend you write a function that creates a new Stock() class object and must therefore set name & price variables for it.  We would first have to check if one is set and then the other:

if let someName = stock.name {

if let somePrice = stock.price {

//now we can do something with price…

}

}

This would get messy.  So we chain them into a single statement like so:

someVariableWeWantToSet = stockName?.stockPrice

Takeaway #10: Many ObjC framework objects are optionals? and many are implicitly unwrapped! when passed into functions because they will start out as nil (UILabels, MKAnnotationViews or MKPolylines) but we know they will eventually get filled in because that’s why we put them there in the first place:

MKAnnotationView!

MKAnnotation!

UIControl!

MKPinAnnotationView!

MKMapView!

Takeaway #11: When we have something like an MKAnnotation! is received in a function as annotation. If we wish to use its super class properties, we must be inline downcast to while if-let checking. Once inside we can implicitly (force) unwrap MKPinAnnotationView! because we know since the annotation exists, it will have a view. For example, in this method:

func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {

if let polylineOverlay = overlay as? MKPolyline {

let renderer = MKPolylineRenderer(polyline: polylineOverlay) renderer.strokeColor = UIColor.blueColor()

return renderer

}

return nil

}

We can interpret that funky as? as follows: “If when I get the variable overlay and unwrap it, it downcasts successfully to a MKPolyline && I get a value (not-nil) then put it into polylineOverlay & continue…” Hope this helps…

Follow

Get every new post delivered to your Inbox.

Join 662 other followers