Categories
Blocks Closures iOS iOS & ObjectiveC Swift

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

Categories
Blocks Closures iOS Swift

HealthKit for iOS8: Part 4

iOS 8 HealthKit Santiapps Marcio Valenzuela
iOS 8 HealthKit

Ok so the Journal view controller was quite simple.  Let’s take another quick break by looking at an even simpler view controller, the FoodPicker:

import Foundation

import UIKit

import HealthKit

class FoodPickerViewController: UITableViewController {

var selectedFoodItem: FoodItem?

let FoodPickerViewControllerTableViewCellIdentifier:NSString = "cell"

let FoodPickerViewControllerUnwindSegueIdentifier:NSString = "FoodPickerViewControllerUnwindSegueIdentifier"

var foodItems: NSArray = NSArray()

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?

}

Here we are looking at imports, subclassing UITableViewController and property declarations.

Our first property is selectedFoodItem, which will be set to whatever value the user selects from this tableview as an item that he or she consumed.  Then we have 2 identifiers, one for our tableviewcell and another for our unwind segue.  Remember to set both in the storyboard.  To set the cell identifier you must select the cell in the tableview and for the unwind segue you must select the segue from the “Add” button in Journal to the FoodPicker.  Then we create an array to store the hard coded values of our FoodItems.  Ideally you might want to pull this data from a web service.

Notice we use the NSEnergyFormatter here again.  You could also just create a class for this and access it globally.  Finally we add our health store variable.

Now let’s look at our viewDidLoad method:

override func viewDidLoad() {

super.viewDidLoad()

self.foodItems = [FoodItem(name: "Wheat Bagel", joules:240000.0),

FoodItem(name: "Bran with Raisins", joules:190000.0),

FoodItem(name: "Regular Instant Coffee", joules:1000.0),

FoodItem(name: "Banana", joules:439320.0),

FoodItem(name: "Cranberry Bagel", joules:416000.0),

FoodItem(name: "Oatmeal", joules:150000.0),

FoodItem(name: "Fruits Salad", joules:60000.0),

FoodItem(name: "Fried Sea Bass", joules:200000.0),

FoodItem(name: "Chips", joules:190000.0),

FoodItem(name: "Chicken Taco", joules:170000.0) ]

}

Nothing special here, just hardcoding some FoodItems into our array.  So now our tableview methods:

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

return self.foodItems.count

}

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

let cell: UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier(FoodPickerViewControllerTableViewCellIdentifier, 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;

}

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

NSLog("performing unwind segue from FOODPICKER!")

if (segue.identifier == FoodPickerViewControllerUnwindSegueIdentifier) {

var indexPathForSelectedRow: NSIndexPath = self.tableView.indexPathForSelectedRow()!

self.selectedFoodItem = self.foodItems[indexPathForSelectedRow.row] as? FoodItem

}

}

There, now that’s a nice breather.   We set our rows according to the number of items in the array, set our cell values in the same way we did before.  And in our prepareForSegue method, we check our identifier and then set our own selectedFoodItem property from whatever the user selected.

Ok so you’ve had 2 easy classes to rest.  Now let’s get into the longest one, Part 5.

Categories
iOS Iphone Developer Swift

Swift Optionals Quick Reference

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…