Split View Controller

This is known as a split view controller, where there is a view controller on the left that takes up about 30% of the space, and a view controller on the right that takes up 70% of the screen estate.

In portrait mode, there is a button to tap which brings up a view controller known as a Popover Controller. This PopoverController is the exact same controller that was on the left in the previous slide.

Let’s start off first with a Split View Controller. We simply create it as usual, and then set the viewControllers property to an array of view controllers. Take note that we should only have two view controllers here.

 

Create split view controller

UISplitViewController* splitVC = [[UISplitViewController alloc] init];

 

Set viewControllers 

splitVC.viewControllers = [NSArray arrayWithObjects:firstVC, secondVC, nil];

 

For the popover controller, it is slightly different. We have to create the controller with an already existing view controller and set the delegate. Furthermore, we need to have a custom property that contains this popoverController.
After which, we can present the popover from a UIBarButtonItem or a rectangle. In here, permittedArrowDirections means which way the arrow of the popovercontroller can point.

 

Create Popover Controller/set delegate

UIPopoverController* aPopover = [[UIPopoverController alloc] initWithContentViewController:content];
aPopover.delegate = self;

 

Set in custom property
self.popoverController = aPopover;

 

Present controller

[self.popoverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

[popoverController presentPopoverFromRect:CGRectMake(0,0,100,100) inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

 

As mentioned earlier, the view controllers in the split view controller and the popover controller are the same. We have to do a bit of extra work to ensure all is smooth. Let’s first take care of it when the iPad rotates from a landscape to a portrait orientation. Firstly, the delegate method, willHideViewController withBarButtonItem forPopoverController will be called. In here, we have to point the UIBarButtonItem which has been created by the method and set it to our popoverController property which we have. This is where the property comes into use.

 

Supporting Orientation Changes

// Called when rotating to a portrait orientation. 
– (void)splitViewController: (UISplitViewController*)svc willHideViewController:
(UIViewController *)aViewController withBarButtonItem: (UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc{
barButtonItem.title = @”Root List”; 
NSMutableArray *items = [[toolbar items] mutableCopy]; 
[items insertObject:barButtonItem atIndex:0]; [toolbar setItems:items animated:YES]; 
[items release]; 
self.popoverController = pc;

}

 

When we rotate it back to the landscape position, we do the exact opposite, by removing the UIBarButtonItem and setting the popoverController to be nil.

 

Supporting Orientation Changes

// Called when the view is shown again in the split view, invalidating the button and popover controller.

– (void)splitViewController: (UISplitViewController*)svc willShowViewController: (UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem
*)barButtonItem {
NSMutableArray *items = [[toolbar items] mutableCopy]; 
[items removeObjectAtIndex:0]; 
[toolbar setItems:items animated:YES]; 
[items release]; 
self.popoverController = nil;

}

UITouch

Let’s have a look at touchesBegan. When touchesBegan is called, it returns an event. We can call allTouches to get the touches and then locate the first touch. Each touch has many properties, including tapCount, timeStamp and the view it was contained in. We can manipulate these to create whatever desired action we want.

Touches
-(void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event { NSSet *allTouches = [event allTouches];
//first touch
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];

Understanding each touch

tapCount
timeStamp

view

Gesture Recognizers
If you want to detect gestures, there’s an app for that. But you have to build it. However, Apple has created recognizers called UIGestureRecognizers which save lives. You can easily detect motions and gestures such as tapping, pinching, panning, swiping, rotating, and long presses. They are extremely easy to add and customize, and include delegates for further customization.

UIGestureRecognizer

UITapGestureRecognizer *doubleFingerDTap =
[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleDoubleTap:)];

Add to view

[self.view add doubleFingerDTap];

Let’s look at how we can use them. First we create the UIGestureRecognizer, in this case, we use a UITapGestureRecognizer.
We add it to the view, and implement the delegate if we want. Now, the delegate has important methods such as requiring other gesture recognizers to fail. For instance, if you have a singleTapGestureRecognizer and a doubleTapGestureRecognizer, you would need the double tap gesture to fail before recognizing the single tap. That means, you will have to wait for a few seconds to confirm that it is not a double tap, before performing the single tap action.

UIImagePickerController

Let’s dive into the hardware of the iPhone and iPad, both of which now have a camera.

UIImagePickerController
The default use of a camera in iOS applications is the UIImagePickerController. You can take pictures from the Photo Library, Saved Photos, or Camera itself.
There are certain steps you need to take when you want to implement UIImagePickerController into your apps. First off, you need to check the source availability. Some devices do not have cameras, and thus this step is crucial (although Apple does check for you as well, it is good to check it yourself to be sure). Next step is to set the source type, which is where you want to select the photos from, be it the camera or photo library or saved photos. After which, you would want to set properties such as the media types, photo or video. Finally, you assign the delegate to yourself and present the controller modally. Take note that these controllers are always modally presented.

//Check source availability
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])
{
//Create UIImagePickerController
UIImagePickerController* picker = [[UIImagePickerController alloc] init];

//Set image picker source
picker.sourceType = UIImagePickerControllerSourceTypeCamera;

//Set image picker media types
picker.mediaTypes = [NSArray arrayWithObjects: (NSString *) kUTTypeMovie, (NSString *) kUTTypeImage, nil];

//Set image picker delegate
picker.delegate = self;

//Present image picker
[self presentModalViewController:picker animated:YES];

}

* Add MobileCoreServices.framework or
 #import

First off, we check the source availability by calling isSourceTypeAvailable. Next we create the UIImagePickerController, set the source and mediaTypes. For mediaTypes we create an array that includes both Movie and Image, in this case. Make sure you add the MobileCoreServices framework and import the UTCoreTypes file first.
Finally, we set the delegate to the view controller and present it modally.

There are many properties you might want to take note of while writing for your iOS apps, such as whether to use the rear or front camera, the quality of media, and whether you want to use flash or not.

UIImagePickerControllerDelegate
After implementing all of the above, you still need to implement the delegate methods as well. Your final images or videos will be stored in an NSDictionary that is returned in the imagePickerController didFinishPickingMediaWithInfo. Here is where you would want to store the images somewhere, and then dismiss the controller. There’s also a cancel method if the user chose to cancel taking a photo instead.

Contains your original and edited images (save them!)

– (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info; 

Dismiss controller here
– (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;

After implementing all of the above, you still need to implement the delegate methods as well. Your final images or videos will be stored in an NSDictionary that is returned in the imagePickerController didFinishPickingMediaWithInfo. Here is where you would want to store the images somewhere, and then dismiss the controller. There’s also a cancel method if the user chose to cancel taking a photo instead.

Saving Media
To save media, we have to use the following methods, UIImageWriteToSavedPhotosAlbum, and UISaveVideoAtPathToSavedPhotosAlbum. For videos, you need to check if the path is compatible to be saved in.

UIImageWriteToSavedPhotosAlbum

Optional completion callback 

UIVideoAtPathIsCompatibleWithSavedPhotosAlbum 
UISaveVideoAtPathToSavedPhotosAlbum

Augmented Reality
If you want to use augmented reality in your apps, you definitely can. The few properties that you should be looking at are showsCameraControls, cameraOverlayView, and cameraViewTransform. A third party kit that was recently developed is available for free to incorporate into your apps at www.iphonear.org.

ARKit (http://www.iphonear.org)

showsCameraControls
cameraOverlayView 

cameraViewTransform

Web Services XML or JSON

Most web services are exposed via RESTful interfaces such as XML or JSON.

XML
XML looks like this. Basically it starts off with the version number, and then a dictionary or array within. This dictionary or array can contain even more dictionaries and arrays or any other objects. The next thing we have to do is to parse through this message.


Steve Paul Have a good weekend!

XML Parsers
There are two types of XML parsers, the DOM and SAX parsers. The DOM notifies you when it runs through the tree. A SAX parser reads and builds up an in-memory representation of the XML. Both has its advantages and disadvantages.

Many to choose from (C / Obj-C)
NSXML, 
libxml2
TBXML
TouchXML
KissXML
TinyXML
GDataXML

Advantages/drawbacks
Validation
XPath

For the parser itself, we have many to choose from. The included parsers are NSXMLParser and libxml2 parser. The rest are created by third-party developers and have proven to work. Each parser, again has its own advantages / disadvantages to watch out for, such as validation of each step as it parses through the XML, and also XPath which functions as an index.

NSXMLParser
Let’s run through the included XML parser, NSXMLParser. The first thing you have to do is to create the parser, set the delegate to self, and any properties you may wish to set. During the creation of the XMLParser, be sure to init with whatever XML you have.

Create parser/set delegate & properties

NSXMLParser *parser = [[NSXMLParser alloc] initWithURL:myURL];
parser.delegate = self;
parser.shouldProcessNameSpaces = NO;

Parse

[parser parse];

Receive from delegate methods

 – (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
– (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName 
 – (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string

JSON
Another form of RESTful interface is JSON, which is Javascript Object Notation. Here’s how the same message looks like in JSON. This is more human-readable, according to many.
To parse JSON, we can use a third-party JSON framework, called SBJSON. SBJSON was created by Stig Brautaset. It was originally named JSON-framework but renamed soon after to SBJSON.

SBJSON
To use SBJSON, we simply download, drag and copy into our own project. If you are using XCode 4, you might want to check out how to link projects instead of copying them over. The instructions are a bit more complicated, but are also found in the same SBJSON link.
The next thing we need to do is to import JSON.h, create the SBJSON parser, and then parse it into an NSDictionary. If we do not know what the final object is, we can simply use the id type. Download, drag and drop, copy into folder.

Import/create/parse

#import “JSON.h”
SBJSON *parser = [[SBJSON alloc] init];
NSDictionary *object = [parser objectWithString:json_string error:nil];

NSUserDefaults

There are a few ways we can persist data on the iPhone. The first one is to store data securely. We can make use of the Keychain framework that Apple has provided.
NSUserDefaults is another way of storing data, but for non-sensitive info such as user settings which do not need to be encrypted. NSUserDefaults will be further explained in the next slide.

Set a value
[[NSUserDefaults standardUserDefaults] setObject:myValue forKey:myKey];

Retrieve a value
[[NSUserDefaults standardUserDefaults] objectForKey:myKey];

Synchronize
[[NSUserDefaults standardUserDefaults] synchronize];

NSUserDefaults is a simple way of storing non-sensitive data. We can set a value by calling NSUserDefaults standardUserDefaults set Object. Basically, it works like an NSDictionary. You can easily set and retrieve values.
However, this time round, you need to synchronize. Synchronize basically works like a save. After changing variables, you might want to call synchronize to save NSUserDefaults. NSUserDefaults saves every now and then, but to make sure you can simply call synchronize.