Orientating Yourself in iOS

Working with device orientation is essential when building apps on a tablet. Users simply expect your app to work in all orientations. Games are the only apps typically exempt from this expectation. And, while the subject seems basic, how to detect and respond to the orientation of the device isn’t clear. I’ve seen people recommend multiple ways to determine the screen’s orientation:

You can access the UIDeviceOrientation *orientation via the current device itself:

// Not necessary for screen redrawing
[[UIDevice currentDevice] orientation]

Or you can access the UIInterfaceOrientation *interfaceOrientation via the sharedApplication:

// Reliable but not recommended
[[UIApplication sharedApplication] statusBarOrientation]

Or you can simply pull the UIInterfaceOrientation *interfaceOrientation from within your view controller as a standard property provided to you from the SDK:

// BEST METHOD (most of the time)
self.interfaceOrientation

What’s the difference between Device and Interface Orientations?

The short answer is that you’ll probably only care about UIInterfaceOrientation. UIInterfaceOrientation only covers the possible orientations for the screen in regards to drawing:

UIInterfaceOrientationPortrait == UIDeviceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown == UIDeviceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft == UIDeviceOrientationLandscapeRight
UIInterfaceOrientationLandscapeRight == UIDeviceOrientationLandscapeLeft

Where UIDeviceOrientation provides six different options that represent the actual orientation of the device in 3D space. When redrawing your layout, you probably won’t need to know all of these:

UIDeviceOrientationUnknown                    // Can't be determined
UIDeviceOrientationPortrait                   // Home button facing down
UIDeviceOrientationPortraitUpsideDown         // Home button facing up
UIDeviceOrientationLandscapeLeft              // Home button facing right
UIDeviceOrientationLandscapeRight             // Home button facing left
UIDeviceOrientationFaceUp                     // Flat with screen facing up
UIDeviceOrientationFaceDown                   // Flat with screen facing down

How can I Determine the Interface Orientation?

While you could simply use equality operators in an if statement to compare the current orientation against the possible orientation types listed above, Apple has provided some nice macros to help you. Just remember that UIDeviceOrientation and UIInterfaceOrientation have their own macros. Do not mix and match the different orientation enums. The compiler in XCode should provide you with plenty of warnings if you do.

// For UIInterfaceOrientations
UIInterfaceOrientationIsLandscape(UIInterfaceOrientation orientation)
UIInterfaceOrientationIsPortrait(UIInterfaceOrientation orientation)

// For UIDeviceOrientations
UIDeviceOrientationIsLandscape(UIDeviceOrientation orientation)
UIDeviceOrientationIsPortrait(UIDeviceOrientation orientation)

When can I determine the orientation?

Judging from the volume of questions I’ve seen on StackOverflow and other forums, many people run into an issue where the macros mentioned above always return true for portrait (or vice versa). Often this is because self.interfaceOrientation returns NULL when a view initially loads. They simply are checking the screen orientation at the wrong time. You will not have access to the current orientation in your view controller until the view is about to be presented. This means you should handle any interface drawing in the viewWillAppear: or viewDidAppear: methods.

-(void)viewDidLoad {
  self.interfaceOrientation // NULL
}

-(void)viewWillAppear:(BOOL)animated {
  self.interfaceOrientation // UIInterfaceOrientationLandscapeLeft
}

Which method works best?

First off, I recommend avoiding UIDeviceOrientation unless you’re doing something really specific, in which case you must have a reason to want to use UIDeviceOrientation. If you don’t know why you’re using UIDeviceOrientation you probably shouldn’t be using it.

Second, if you’re working within a UIViewController or subclass of UIViewController I would rely on the self.interfaceOrientation property. This is what Apple wants you to use and it’s also the most convenient.

And last but not least, if you’re working in a UIView or subclass of UIView the convenient property won’t exist. In which case you’ll want to access the orientation of the status bar from the shared application. That’s the code that looks like this:

[[UIApplication sharedApplication] statusBarOrientation]

The sharedApplication solution seems to be the most popular solution, mainly because it works almost anywhere, but I personally see it as a bit of a hack. Only use this if you really need to. You shouldn’t need to react to interface orientation within a UIView. This is the job of a UIViewController. But if you find yourself in the need of a quick fix in a messy project, this is a dirty solution to get what you want. Just remember to wash your hands after you use it.