HealthKit for iOS8: Part 3

HealthKit iOS8 by Santiapps.com
HealthKit iOS8

Great!  Now let’s move on to the Journal View Controller.  It’ll be a good relax! 🙂 Ok we start out importing the frameworks we need:

import UIKit
import HealthKit

Ok now let’s declare our class properties:

class JournalViewController: UITableViewController {     
let JournalViewControllerTableViewCellReuseIdentifier: NSString = "Cell"     
var foodItems: NSMutableArray?     
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!     
}      
var  healthStore:HKHealthStore? 
}

The first thing to note, is that once again this is UITableViewController.  However, unlike Profile, this tableview will contain dynamic, prototype cells.  Thus we need to dequeue our cells to save memory.  The first constant we need is one for our table view cell identifier.  Then we create a mutable array to hold our selected food items, which will come from the user selecting them in the FoodPicker. The next property is a bit strange.  NSEnergyFormatter is something new and health kit uses it to format energy data.  This is a computed property, which means it is computed each time you call for it.  This is basically creating an energyFormatter much in the same way you would create an dateFormatter from NSDateFormatter. Then finally there is the healthstore property which we need and set from the AppDelegate as you recall. Next up we have our view controller lifecycle methods which kick things off:

override func viewDidLoad() {         
super.viewDidLoad()         
self.foodItems = NSMutableArray()         
self.updateJournal()         
NSNotificationCenter.defaultCenter().addObserver(self, selector: "updateJournal", name: UIApplicationDidBecomeActiveNotification, object: nil)     }     
override func viewDidDisappear(animated: Bool) {         
NSNotificationCenter.defaultCenter().removeObserver(self, name:UIApplicationDidBecomeActiveNotification, object:nil)     
}

Our viewDidLoad does 2 things; instantiates a mutable array for foodItems so the user can start putting things in there and it calls updateJournal which we will write next.  This view controller also sets itself up as an observer for notifications fired whenever the app becomes active and finally in the viewDidDisappear method we remove ourselves as an observer. Now let’s write updateJournal.  The purpose of this method will be to basically update this tableview with data gotten from the FoodPicker after the user selects items he or she consumed:

func updateJournal () -> () {
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)!

var sampleType: HKSampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)
var predicate: NSPredicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate:endDate, options:.None)

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!")
}
dispatch_async(dispatch_get_main_queue(), {

// PARSE RESULTS INTO ARRAY, RELOAD DATA ALL ON MAIN QUEUE
self.foodItems?.removeAllObjects()
for sample in results as [HKQuantitySample] {                 
NSLog("sample is= \(sample.metadata)")
let foodMetadataDict = (sample.metadata as NSDictionary)
let foodThing: AnyObject? = foodMetadataDict.objectForKey("HKMetadataKeyFoodType")                 NSLog("\(foodThing)")

let foodName = foodThing as NSString
let joules: Double = sample.quantity.doubleValueForUnit(HKUnit.jouleUnit())             
let foodItem: FoodItem = FoodItem(name: foodName, joules:joules) as FoodItem                 self.foodItems?.addObject(foodItem)
}             
self.tableView.reloadData()
})
}
self.healthStore?.executeQuery(query)     // EXECUTE QUERY  }

Ok, its a bit long but simple.  The first few lines create a date for our query.  Then we create a sampleType for DietaryEnergyConsumed which is a data type health store can read and write.  We then create a predicate for it which basically limits the query to today.  Finally we create the query object and execute it (in the last line).

Remember, whats inside the query body is actually a completion block.  We pass the query the sampleType, dates and completion handler.  That completion handler takes a result and an error once again.  If there is an error, we log, if we get results from the query then we log that we got something!  Thats just being silly, but then the query code goes on to a dispatch queue.

This is where we will now update the UI by removing all objects in our foodItems array, and then for every HKQuantitySample in results array, we get the metadata key that we  will store in the object array as part of the FoodItem object and get it as a NSString.

Finally we get the value for that quantity and create a fully qualified FoodItem with that data.  In the end we add that FoodItem to the array and reload the table data. Well now that we mentioned FoodItem, let’s take a look at that class and it’ll help you better understand the next method which is the actual method for adding a FoodItem’s data to the health store.  So here is the FoodItem class:

import Foundation
import HealthKit

class FoodItem {
var name: NSString
var joules:  Double
init (name:NSString, joules:Double) {
self.name = name
self.joules = joules
}

func isEqual(object:AnyObject) -> (Bool) {
if object.isKindOfClass(FoodItem) {
return ((object as FoodItem).joules == self.joules) && (self.name == (object as FoodItem).name)
}
return false;
}

func description(NSString) -> (NSString){
var descriptionDict: NSDictionary = [ "name" : self.name, "joules" : self.joules ]
return descriptionDict.description as NSString
}
}

That was short and sweet!  First we declare the properties of our FoodItem class, name and joules.  Then we create the initializer for it, important to note!  We also added an isEqual function in there to test if an object is a FoodItem type object.  Remember that FoodItem is not subclassing NSObject so it doesn’t have access to NSObject’s isEqual function.  Finally we give FoodItem a description function which basically returns its name and joules values as an NSString. Sweet!  Ok so now let’s look at the Journal view controller method that actually adds a FoodItem:

func addFoodItem (foodItem:FoodItem) {         
// MUST DEFINE HKQUANTITY_TYPE         
var quantityType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)         //MUST DEFINE HKQUANTITY         
var quantity: HKQuantity = HKQuantity(unit: HKUnit.jouleUnit(), doubleValue:foodItem.joules)         //DATE & METADATA         
var now: NSDate = NSDate()         
var metadata: NSDictionary = ["HKMetadataKeyFoodType":foodItem.name]         
//This creates the object to SAVE         
var calorieSample: HKQuantitySample = HKQuantitySample(type: quantityType, quantity:quantity, startDate:now, endDate:now, metadata:metadata)          
NSLog("Before saving to health store in Journal...")         self.healthStore?.saveObject(calorieSample, withCompletion: { (success, error) in             NSLog("After saving to healthstore in Journal...")             dispatch_async(dispatch_get_main_queue(), {                 
NSLog("After dispatch to health store in Journal...")                 
if success {                     //MUST UPDATE TABLE in MAIN QUEUE                     NSLog("Energy Consumed Saved")                     
self.foodItems?.insertObject(foodItem, atIndex:0)                     
var indexPathForInsertedFoodItem: NSIndexPath = NSIndexPath(forRow: 0, inSection: 0)                     self.tableView.insertRowsAtIndexPaths([indexPathForInsertedFoodItem], withRowAnimation: UITableViewRowAnimation.Automatic)                 
} else {                     
NSLog("An error occured saving the food %@. In your app, try to handle this gracefully. The error was: %@.", foodItem.name, error)                     
abort()                 
}             
})         
})     
}

It seems long, but the pattern is pretty simple.  We create the right identifier for DietaryEnergyConsumed, we create a quantity from the FoodItem we passed into this method, specifically from its joules value.  We create a date and give it some metadata in order to complete the creation of our HKQuantitySample.  Finally we saveObject to the health store and in its completion block, if success we log Energy Consumed Saved, insert the newly selected item into the foodItems array and update the tableview.  Otherwise we log the error. Finally let’s look at our tableview methods and our segue method because remember that from this Journal view controller we will allow the user to tap the “Add” button to take us to the FoodPicker which we will analyze next.  So here are our tableview and segue methods:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {         return self.foodItems!.count     }

We set our numberOfRowsInSection to the items in our mutable foodItems array.

override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell {         
let cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath:indexPath!) as UITableViewCell          
var foodItem: FoodItem = self.foodItems?[indexPath!.row] as FoodItem         cell.textLabel.text = foodItem.name          
cell.detailTextLabel!.text = energyFormatter.stringFromJoules(foodItem.joules)         
return cell;     
}

Here we dequeue a cell as always and create a FoodItem according to the indexPath!.row and get its name and joules into the cell.

func performUnwindSegue(segue:UIStoryboardSegue) { //was typed as ibaction...         
var foodPickerViewController: FoodPickerViewController = segue.sourceViewController as FoodPickerViewController         
var selectedFoodItem: FoodItem = foodPickerViewController.selectedFoodItem! as FoodItem       self.addFoodItem(selectedFoodItem)     
}

As for the segue, this is the initiating view controller, so we need an unwind because when the user finishes selecting an item in the FoodPicker, we must do some stuff.  What stuff?  Well first we get our sourceViewController for the “unwind” segue.  Don’t get confused because normally you get the destination segue of a forward segue in order to set that destination view controller’s properties.  In this case, we are in the calling view controller and we are unwinding from a segue.  Our source view controller is FoodPicker and our destination is Journal.  We then take the source’s selectedFoodItem property and set it as a local variable called selectedFoodItem here, locally, in Journal.  Then we call our addFoodItem() method passing it in that local variable selectedFoodItem.  That saves that food item’s name in metadata and its joules into the health store as DietaryConsumedEnergy. Well, that was quite simple.  The FoodPicker is actually quite simple.  See you there (Part 4)!

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

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")

iOS : Swift : Blocks = Closures

Closure on closures
Closure on closures

I’ve never really liked blocks in ObjC.

When Swift came out it made things more complicated for me because I’ve never really liked C either.

Finally when I had to deal with closures in Swift, well that’s just gonna piss a lot of people off!

After a few days reviewing tons of material online, and I mean TONS!  I came to understand this:

The only C-like exposure I had prior to ObjC was a little PHP.  So that allows me to understand a function, which is the equivalent of a method in ObjC:

DECLARING

func sayHello( ) {

     println(“Hello World”)

}

CALLING

sayHello( )

RESULT

Hello World

Even if you didn’t have any exposure to C or PHP or some other “not-so-friendly” language as ObjC, you can surely understand that

  1. The function is called sayHello
  2. That it takes no input-parameters because the ( ) is empty
  3. That it has no return type because it returns nothing since its missing the keyword “return” inside of it 🙂
  4. And that all it does, instead of returning a value, is print out Hello World

Just to clarify, let’s look at a function with a return value:

DECLARING

func sayHello () -> String {

    var result = “Hello World”

    return result

}

CALLING

var whoAreYou = sayHello()

RESULT (value of whoAreYou)

Hello World

As you can see here, we actually return a value from this function, which we can assign to a variable.  I had to assign it to a variable so that it made sense to actually return a value from a function.  

So we added an output-value to an otherwise plain vanilla function.  Now lets go for the next kind of function, plain + output + input:

DECLARING

func sayHello (friendOne:String) -> String {

    println(“Hi \(friendOne)”)

    var result = “Hello, ” + friendOne

    return result

}

CALLING

var whoAreYou = sayHello(“Marcio”)

RESULT (value of whoAreYou)

Hello, Marcio

Great!  So you’ve got functions covered:

  • Plain void functions
  • Returning output-value functions
  • Input-Paramter, returning output-value functions

CLOSURES (or blocks from ObjC)

There really is no simple way to explain it in a few words.  But the first thing that stands out from a closure or block, is that IT IS a function, yes!  But it can be passed around like a variable.  So let’s take a look:

var someVariable: String

There, we just declared a variable of type string.  Let’s declare another variable:

var someOtherVariable: ( ) -> ( ) = { }

There, we have just declared another variable, of type…? :s

Simply combine the concepts:

variable = function

And we know that a function is:

function = functionName (input-parameter) -> (Output-value) {some code}

So now say:

variable = function = functionName (input-parameter) -> (Output-value) {some code}

Now drop the middle “function” 🙂

variable = functionName (input-parameter) -> (Output-value) {some code}

If you don’t want the function to have a name, because you are assigning it to a variable anyway, so you can just call it by calling the variable:

variable = (input-parameter) -> (Output-value) {some code}

Hey, that looks a lot like what we had above:

var someOtherVariable: ( ) -> ( ) = { }

Cool!  So what does it all mean Basil?

The important thing is that you will use closures in Swift.  I was working with Parse SDK the other day and I ran into this in Xcode:

Get closure on Closures
Get closure on Closures

This is the first stage of Autocomplete which you may already be familiar with.  It’s telling you this:

Void saveInBackgroundWithBlock(block: PFBooleanResultBlock!(Bool, NSError!) -> Void)

You already know what this means, its just a function/method that takes a block as a parameter.  

This function returns Void, according to the left Void in that line.  

Let’s say that the method is called saveInBackgroundWithBlock ( X ) and it takes 1 parameter, X, where X is a block.

The block is defined as a variable “block:” and its called PFBooleanResultBlock!

It has 2 output-values Bool & NSError.

Now you know how to fill it in.  But wait, there’s more…if you call in the next 15 minutes 🙂

But seriously, Xcode now has something new.  Check it out!  To select that method in the image above, you hit Enter.  This spits out the method signature in the Editor window and expects you to fill in the rest…THE NERVE!  Luckily, you can hit Enter again while that blue selection is highlighting the block and that will give you this:

tah dah!

Get closure on Closures
Get closure on Closures

Now that’s better!  This is Xcode’s new second stage Autocomplete.  Its telling us that the block is defined by { } and it takes 2 input-parameters and returns a Void.  That new “in” keyword serves to separate the return (which is in this case, Void) from the actual code block which follows.

So you can call closures like so:

object.saveInBackgroundWithBlock {succeeded, error in

//some code

}

OR

object.saveInBackgroundWithBlock { (succeeded, error) -> Void in

//some code

}

 OR

object.saveInBackgroundWithBlock( { (succeeded:Bool, error:NSError!) in

//some code

})

OR

object.saveInBackground( { (succeeded:Bool, error:NSError! ) -> Void in } )

OR you can assign it:

var someVar: () -> () = {              

println(“Hello World”)

}

Enjoy!

 

EDIT: In brief:

How to write or declare closures:

{ (succeeded: Bool, error: NSError?) -> Void in /* code */ }
{ (succeeded: Bool, error: NSError?) in /* code */ }
{ (succeeded, error) in /* code */ }
{ succeeded, error in /* code */ }
{ /* code using $0 for succeeded and $1 for error */ }

How to pass a closure:

object.saveInBackgroundWithBlock({ /* closure */ })
object.saveInBackgroundWithBlock() { /* closure */ }   // Only if closure is last arg
object.saveInBackgroundWithBlock { /* closure */ }     // Only if closure is only arg