Adam Luptak

Device Orientation in iOS

Objective-C
Oct. 29, 2013

Let me tell you a story: there once was an iOS app that was primarily locked into a portrait orientation, but had a photo viewer that could support landscape. The systems for governing orientation were complex and not clearly explained anywhere, and clear answers on Stack Overflow were hard to come by.

In the end, we figured it out. The trickiest part was figuring out how to keep the app from launching in a forbidden orientation, but still allow the orientation in the photo viewer. Here's what we learned.

Project Settings > General > Deployment Info

This is easy. For each targeted device, select orientations that the app can be launched into. If the device is in an orientation that isn't included here when the app is launched, it will snap to one that is.

View Controller Orientation Methods

The app's root view controller has some methods for controlling rotation.
In iOS 5 (and before), -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation is used. It overrides the orientations listed in the project's Deployment Info.
In iOS 6 (and later), we instead use -(NSUInteger)supportedInterfaceOrientations and return a UIInterfaceOrientationMask value.
However, in iOS 6 and later, supportedInterfaceOrientations does NOT override the settings in Deployment Info, but rather can be used to disable orientations enumerated in the Deployment Info.

App Delegate

In iOS 6 (and later), there is an optional method that can be implemented in the App Delegate: -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window. If implemented, this will kick in after the app launches, and override the orientations listed in the Deployment Info.

So, in our example, we want the app limited to portrait at launch and throughout the app, except in the photo viewer.
In Deployment Info, only portrait is allowed.
For iOS 6 and later, application:supportedInterfaceOrientationsForWindow: overrides the Deployment Info (once the app is launched) by returning UIInterfaceOrientationMaskAll.
The root view controller is set up to call shouldAutorotateToInterfaceOrientation: and supportedInterfaceOrientations on the top view controller on the stack and return the result.
In iOS 5, shouldAutorotateToInterfaceOrientation: returns YES only if interfaceOrientation is UIInterfaceOrientationPortrait, except in the case of the view controller for the photo viewer, which always returns YES.
In iOS 6, supportedInterfaceOrientations returns UIInterfaceOrientationMaskPortrait, except the photo viewer, which returns UIInterfaceOrientationMaskAll.