With thousands of API changes in iOS 8, developers have been hard at work updating their apps to support the latest version of iOS. Many hope to have their apps ready in the App Store when iOS 8 launches on September 17.

For those of you still working through the changes, here are some tips for your development on iPhone 6 and iOS 8.

This post is intended for beginner and intermediate developers. Code samples are in Objective-C, but can be rewritten in Swift. This post will be updated as more information becomes available.

iPhone and iPad screen sizes

In the past, we’ve only had to deal with three point resolutions on iOS:

320 x 480 (iPhone 4s and earlier)

320 x 568 (iPhone 5 and later)

768 x 1024 (iPad)

In addition to that, there were only two pixel densities: regular (1x) and Retina (2x).

Now there are two additional point sizes to consider:

375 x 667, with 2x Retina pixel density, for iPhone 6

414 x 736, with 3x Retina pixel density, for iPhone 6 Plus (some scaling is involved)

Can your app handle all of these resolutions?

“I can take it. The tougher it gets, the cooler I get.”

Richard M. Nixon

Which Display is This?

If you’re working on an existing app, you might be checking if you’re on an iPad or iPhone by checking the view’s width:

if (CGRectGetWidth(self.frame) == 320) {

/* Do something for iPhone */

}

This test will no longer produce the results you’re looking for.

Another approach is testing the device idiom:

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)) {

/* Present a UITableViewController subclass */

} else {

/* Present a UISplitViewController subclass */

}

This may produce the results you want, but probably won’t. It won’t natively take advantage of all of your screen real estate, especially in landscape mode.

Instead, consider that with iPhone 6 Plus, you’ll likely want an iPhone-style UI in portrait, and an iPad-style UI in landscape.

For example, suppose you have an award-winning app, FireStarter, and it looks like this in landscape on iPad:

Former US president Richard Nixon, presented in landscape orientation on iPad, clenches his fist in a decisive show of fearless leadership.

If your code only checks the device idiom, here’s how your user interface would look on iPhone 6 Plus:

Nixon established the Environmental Protection Agency (EPA) in 1970.

Obviously, users will be frustrated if you allocate 100% of their 5.5 inches of Retina HD screen real estate to listing five items on a table. Instead, we want it to look more iPad-esque:

Rumors indicate that OS X 10.11 will be named “OS X Yorba Linda” after Nixon’s birthplace

To implement this yourself, the easiest way is to learn about iOS 8's Split View Controller behavior.

iOS 8 Split View Controller and Size Classes

Since the dawn of time, UISplitViewController has only been available on iPad. Starting with iOS 8, the Split View Controller now works on iPad and iPhone.

Size Classes

To accommodate these different devices, iOS 8 introduced size classes. These are intended to replace both UIInterfaceOrientation and UIUserInterfaceIdiom. There are four:

Horizontal Regular

Horizontal Compact

Vertical Regular

Vertical Compact

In iOS 8, these can be accessed on a view controller’s traitCollection property, and traitCollectionDidChange: will get called if it changes, for example on device rotation.

iOS devices and their size classes

Full-screen view controllers on iPad are always “regular”. On iPhones before iPhone 6, the vertical dimension is always “compact” and the horizontal dimension is only “regular” in portrait mode. With the larger iPhones introduced today, the vertical dimension will now be “regular” in landscape mode.

By adopting size classes, you can provide your normal iPhone UI in portrait, and an iPad-like UI in landscape on iPhone 6. For example, if you’re making a cookbook app, you might show a unit conversion widget for “regular” but hide it for “compact”:

if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {

/* Hide the extra details */

} else if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) {

/* Show the extra details */

}

You can override the trait collection for a view controller. This would allow you to use the “regular” interface on smaller iPhones in landscape.

Split View Controller’s Use of Size Classes

If your app has a standard master-detail UI, you can simplify a lot of this by just using a split view controller instead of writing the logic yourself.

Here’s how it works:

If the controller’s traits include horizontal regular , the two controllers are presented side-by-side, like in the above screenshot.

, the two controllers are presented side-by-side, like in the above screenshot. If the controller’s traits include horizontal compact, the primary view controller is displayed, and the secondary view controller is pushed or popped as needed.

There are some exceptions to this behavior noted in the documentation. This behavior can also be customized by implementing a UISplitViewControllerDelegate object and by setting the preferredDisplayMode property. For example, you might want to set this property to UISplitViewControllerDisplayModeOverlay if you want the iPad-style popover on iPhone.

New Rotation Behavior in iOS 8

iOS 8 deprecates all rotation methods in favor of one: viewWillTransitionToSize:withTransitionCoordinator:. This method is called on a view controller when the size of its view is about to change. This can happen for many reasons, for example:

The user rotated the device

The status bar got larger (for example, during Voice Memo recording or an incoming phone call)

A higher-level view controller resized this view controller’s view

If you’re using basic auto-layout and your constraints don’t need to be updated, you may not need to implement this method at all. If you are using frame-based layout, or need to perform some calculations to update auto-layout constraint constants, this method is the place to do it.

A typical implementation will call super and then tell the animation coordinator what to change:

-(void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {

[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {

/* Reorganize views, or move child view controllers */

} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {

/* Do any cleanup, if necessary */

}];

}

The animation coordinator will animate the changes you specify along with all of the others at the same time.

HealthKit and Apple Watch

Apple Watch contains a bunch of sensors like an accelerometer, a heart rate sensor, and more. iPhone 6 also contains new sensors that can more accurately measure distance and elevation. Health data is stored in iOS 8's new Health app and it can also be accessed in your app via HealthKit.

Apple has provided excellent sample code, a WWDC video (transcript; PDF), so we‘ll just cover the basics here.

If you’ve used Apple’s other permissions-based APIs, though, it should look familiar. Getting permission is asynchronous and block-based:

self.healthStore = [[HKHealthStore alloc] init]; if ([HKHealthStore isHealthDataAvailable]) {

NSSet *writeDataTypes = /* info you want to write */

NSSet *readDataTypes = /* info you want to read */ [self.healthStore requestAuthorizationToShareTypes:writeDataTypes readTypes:readDataTypes completion:^(BOOL success, NSError *error) {

if (success) {

dispatch_async(dispatch_get_main_queue(), ^{

/* Do something with the user’s health info */

});

} else {

/* Permission denied, or some other error */

}

}];

}

Some information can be obtained by simply asking the health store:

NSError *err;

NSDate *dateOfBirth = [self.healthStore dateOfBirthWithError:&err];



if ([dateOfBirth isEqualToDate:self.birthday]) {

/* Order Birthday Cake 🎂 */

}

More complex information, including how data has changed over time, can be obtained with different query objects, like HKSampleQuery and HKAnchoredObjectQuery. Also interesting is HKObserverQuery, which will inform your app in real-time as new data is recorded from the sensor.

These queries can help you motivate your customers to live a healthier lifestyle by showing them how far they’ve come.

“Only if you have been in the deepest valley, can you ever know how magnificent it is to be on the highest mountain.”

Richard M. Nixon

Apple Pay (NFC Payments)

Some merchants already have built-in support for Apple Pay in their app:

Target

Groupon

Uber

Panera

Here’s the Apple Pay third-party API documentation, which also lists some supported payment providers. Apple Pay requires that you have a payment processor or gateway, just as if you were taking a credit card. You need to set up certificates and entitlements through the developer portal, and conform to these rules:

Apps using Apple Pay must provide all material purchase information to the user prior to sale of any good or service or they will be rejected Apps using Apple Pay must use Apple Pay branding and user interface elements correctly and as described in the Apple Pay Human Interface Guidelines or they will be rejected Apps using Apple Pay as a purchasing mechanism may not offer goods or services that violate the law of any territory in which the good or service will be delivered and may not be used for any illegal purpose Apps using Apple Pay must provide a privacy policy or they will be rejected Apps using Apple Pay may only share user data acquired via Apple Pay with third parties when provided to facilitate or improve delivery of goods and services or to comply with legal requirements

Your app specifies the contents of the payment:

PKPaymentRequest *request = [[PKPaymentRequest alloc] init];

// configure the request

Present a payment sheet:

PKPaymentAuthorizationViewController *paymentVC = [[PKPaymentAuthorizationViewController alloc] initWithRequest:request];

paymentVC.delegate = self; [self presentViewController:paymentVC animated:YES completion:nil];

If the user approves the payment, your app receives a payment token. Use your payment gateway’s API to authenticate, and call the completion handler once you’re done.

- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus status))completion { /* authorize the payment with your provider */ if (/* it worked */ && completion) {

completion(PKPaymentAuthorizationStatusSuccess);

} else {

/* handle other cases */

}

}

Dismiss the payment controller and inform your users of their order status, approximate shipping time, how to check order status, etc.

Additional Resources

Gaurav Tomar put together an excellent overview of view controller changes in iOS 8. The WWDC video Building Adaptive Apps with UIKit is also incredibly helpful (transcript; PDF).

Shinobi Controls has a thorough introduction to HealthKit that describes the different objects, along with sample code. (If you have a health app, you might want to look at their beautiful graph and chart controls too.)

Stripe has some sample code available for implementing Apple Pay.

If you’re just getting started with iOS development and want to amp up your learning, see my Ultimate Guide to iOS Developer Bootcamps. Also, Bloc (where I work) is giving away a free iPhone 6 to developers who register this month.

More information about Richard Nixon is available on the White House’s presidential history page.

About Me

Aaron Brager, the iOS Director at Bloc, makes iOS apps, and enjoys word play like puns and portmanteaus. He enjoys following the creative output of other Aarons, including Aaron Hillegass, Aaron Rankin, and Aaron Sorkin. He also enjoys playing chess, although he frequently loses.