Beginning Professional iPhone App Development

Christina Moulton, Teak Mobile Inc.

@ChristinaMltn, christina@teakmobile.com

KW iOS Training

Schedule

Session 1: Design Patterns & Obj-C Features, Apple's Tools, SDK & Core Classes

Exercise 1: Interface Builder, IBOutlets & IBActions

Lunch

Session 2: iOS App Ecosystem, 3rd Party Tools & Testing, Key Resources

Exercise 2: JSON REST APIs, Storyboards & Tableviews

Session 3: Code Signing, App Store Submission, What Should Be a Native App vs. Web App

Session 2:

iOS App Ecosystem

3rd Party Tools & Testing

Key Resources

iOS App Ecosystem

Devices, capabilities, resolutions

SDKs

Supporting older devices

Developer Portal

App Store & iTunes Connect

Device Capabilities

iOSSupportMatrix.com

Hardware by capabilities iOS Device Compatibility (Apple)

If not key feature, check for presence & degrade gracefully (e.g., select photo vs. take photo)

Device Resolutions

iOSRes.com

SDKs

SDK iPhone iPad iPod Touch
7 4, 4S, 5, 5C, 5S (June 2010) 2nd, 3rd, 4th, Mini, Mini Retina (March 2011) 5th (Sept 2012)
6.1.3 3GS (June 2009) 4th (Sept 2010)
5.1.1 1st (April 2010) 3rd (Sept 2009)
4.2.1 3G (July 2008) 2nd (Sept 2008)
3.1.3 1st (June 2007) 1st (Sept 2007)

Supporting Older Devices

Check headers / docs or Deploymate

Weak link frameworks (mark as optional)

Check for support at run time

NSString *osVersion = [[UIDevice currentDevice] systemVersion];
if ([anObject respondsToSelector:@selector(aMethod)]) {
    [anObject aMethod];
} else {
    //Fail gracefully
}
// iOS 4.2+
if ([AClass class]) {
    // Safe to use AClass
}

RayWenderlich.com Tutorial

Developer Portal

Apple iOS Dev Center

Links to:

iTunes Connect

Provisioning Profile

Apple Developer Forums

Guidelines, checklists, marketing resources

SDK & Xcode downloads (pre-release)

Documentation, videos & demo code

Human Interface Guidelines (HIG)

iOS 3rd Party Tools & Testing

Beta Testing & Crash Reporting: TestFlight, HockeyApp, Crashlytics

In-App Analytics: Flurry

Sales Analytics: App Annie, Distimo

3rd Party Framework Demo

iOS 3rd Party Tools: BaaS

iOS 3rd Party Libraries & Dependency Management: CocoaPods, AFNetworking, RESTKit

Beta Testing & Crash Reporting: TestFlight, HockeyApp, Crashlytics

Symbolication (.dSYM): Keep your beta & App Store builds!

In-App Analytics: Flurry

Sales Analytics: App Annie / Distimo

Demo: Integrating 3rd Party API: Flurry

Download

Add framework

Import header

Integrate

Customize

iOS 3rd Party Tools: Backend as a Service (BaaS)

Parse, Kinvey, StackMob, Appcelerator Cloud

Provide server-based functionality:

Database shared between users

Social login / user accounts

File storage

Push notifications

Custom server code

Scalability

iOS 3rd Party Libraries

Dependency Management: CocoaPods

RESTful Web Service: RESTKit

Networking Framework: AFNetworking

Custom UI Controls: Cocoa Controls

Lots of Frameworks: iOS Frameworks

Exercise 2: Conference Schedule

Go Open Data Conference

JSON REST APIs, Storyboards & Tableviews

Install & import RESTKit

Create a Session Model Class

Load sessions

Add a tableview in the storyboard

Show the sessions as cells in the storyboard

Tapping on a session should show a larger view of the session with details

Want to try a lower level exercise? Connecting to webservice (RayWenderlich.com)

Install & import RESTKit

First create an empty project

In Xcode preferences menu, go to Downloads then Components. Install or update the Command Line tools

$ sudo gem update --system
$ [sudo] gem install cocoapods
$ pod setup

// Add Podfile to project: In Terminal
$ cd /path/to/MyProject
$ touch Podfile
$ edit Podfile
platform :ios, '6.0' // or '7.0'
pod 'RestKit', '~> 0.20.0'

$ pod install

// Now always use the workspace, not the project
$ open MyProject.xcworkspace
					

Install & import RESTKit

#import <RestKit/RestKit.h>

Add required libraries: SystemConfiguration & MobileCoreServices

Create a Session Model Class

@interface RKConferenceSession : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *sessionDescription;
@property (nonatomic, copy) NSString *start_time;
@property (nonatomic, copy) NSString *end_time;
@property (nonatomic, copy) NSString *type;
@end

RKObjectMapping *mapping = [RKObjectMapping 
mappingForClass:[RKConferenceSession class]];
  [mapping addAttributeMappingsFromDictionary:
  @{@"name": @"name", @"description":@"sessionDescription",
    @"start_time":@"start_time", @"end_time":@"end_time", 
    @"type":@"type",}];

RKResponseDescriptor *descriptor = 
						[RKResponseDescriptor responseDescriptorWithMapping:mapping 
						method:RKRequestMethodAny pathPattern:nil 
						keyPath:@"objects" statusCodes:nil];

Load sessions

NSURL *url = [NSURL URLWithString:
    @"http://api.go-opendata.ca/schedule/?format=json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
RKObjectRequestOperation *operation = 
	[[RKObjectRequestOperation alloc] 
		initWithRequest:request responseDescriptors:@[descriptor]];
[operation setCompletionBlockWithSuccess:
  ^(RKObjectRequestOperation *operation, RKMappingResult *result)
  {
    NSLog(@"The sessions are: %@", [result array]);
    self.sessions = [result array];
  } failure:^(RKObjectRequestOperation *operation, NSError *error)
  {
    NSLog(@"error: %@", error);
    self.sessions = nil;
}];
[operation start];

Add a tableview in the storyboard

Drag & drop

Create a custom UITableViewController subclass & assign it in the storyboard

Add a prototype cell in the storyboard, select the detail style

Show the sessions as cells in the storyboard

Add a property to the tableview to hold the sessions

@interface SessionsTableViewController : UITableViewController
@property (nonatomic, retain) NSArray *sessions;
@end

Move the loading code into the tableview and assign the results to the property when loading is done

- (void)viewDidLoad
{
  [super viewDidLoad];
  
  RKObjectMapping *mapping = ...
  [operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result)
   {
     NSLog(@"The sessions are: %@", [result array]);
     self.sessions = [result array];
     [self.tableView reloadData];
   } failure:^(RKObjectRequestOperation *operation, NSError *error)
   {
     NSLog(@"error: %@", error);
     self.sessions = nil;
     [self.tableView reloadData];
   }];
  [operation start];
}

Show the sessions as cells in the storyboard (continued)

Implement data source & delegate methods:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
  return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
  if (self.sessions != nil)
  {
    return self.sessions.count;
  }
  return 0;
}

Show the sessions as cells in the storyboard (continued)

Implement data source & delegate methods:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  static NSString *CellIdentifier = @"SessionCell";
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
  
  // Configure the cell...
  RKConferenceSession *session = self.sessions[indexPath.row];
  cell.textLabel.text = session.name;
  cell.detailTextLabel.text = session.start_time;
  
  return cell;
}

Tapping on a session should show a larger view of the session with details

In the storyboard, add a detail view with labels to show the details (set lines = 0 for description so it'll auto-resize)

Add a custom UIViewController subclass with IBOutlet properties for each label and a property to hold the Session Model Object

Hook up the outlets in the storyboard

Embed the tableview in a navigation controller

Right-click on the tableview prototype cell and drag a connection to the detail view. Choose "Selection Segue: Push"

Tapping on a session should show a larger view of the session with details (continued)

Now we see the detail view, but the details aren't being set

In the tableview controller, we need to set the properties in prepareForSegue:

#import "SessionDetailViewController.h"

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
  // Figure out which cell they tapped on
  NSInteger selectionIndex = 
    [self.tableView indexPathForSelectedRow].row;
  RKConferenceSession *session = self.sessions[selectionIndex];
  
  // Get the new view controller
  SessionDetailViewController *detailViewController = 
    (SessionDetailViewController *)[segue destinationViewController];
  // Pass the selected object to the new view controller.
  detailViewController.session = session;
}

Tapping on a session should show a larger view of the session with details (continued)

Set all of the label text in the detail view:

- (void)viewWillAppear:(BOOL)animated
{
  [super viewWillAppear:animated];
  if (self.session)
  {
    self.nameLabel.text = self.session.name;
    self.startTimeLabel.text = self.session.start_time;
    self.endTimeLabel.text = self.session.end_time;
    self.typeLabel.text = self.session.type;
    self.descriptionLabel.text = self.session.sessionDescription;
  }
}

Try it!

Questions?

Christina Moulton, Teak Mobile Inc.

@ChristinaMltn, christina@teakmobile.com

KW iOS Training