Difference of UIDeviceOrientation and UIInterfaceOrientation

 
It is important to know the difference of UIDeviceOrientation and UIInterfaceOrientation values, in order to determine what you really need in your application. Most of the time, you will need the UIInterfaceOrientation. But sometimes, especially when dealing with legacy or old style code, or sometimes poorly designed code which you cannot easily redesign or refactor, you will need to rely on UIDeviceOrientation to determine the current orientation.

An example of such poorly designed code is when you have a UIView which handles its own rotation. This is poorly designed because a UIView should not react directly to orientation changes. This is the job of the UIViewController.

Moving on, the UIDeviceOrientation is the current orientation of the device itself, not of the user interface currently displayed within the device. UIInterfaceOrientation, on the other hand, is the current orientation of the target interface. For example, if you use [[UIApplication sharedApplication] statusBarOrientation] in Objective-C or UIApplication.sharedApplication().statusBarOrientation in Swift, you will get the current orientation of the status bar.

There are cases where the UIDeviceOrientation says it is in landscape left, but UIInterfaceOrientation (e.g. status bar orientation) says it is in portrait. This type of case can happen when the currently displayed UIViewController does not rotate (for example, only portrait is supported) and then you try to rotate the device, which means that the actual device can be in landscape but the displayed UIViewController is still displayed in portrait.

Device in Landscape but UI in Portrait

Device in Landscape but UI in Portrait


 
In addition, UIDeviceOrientation has 7 possible values

Objective-C

Swift

 

while UIInterfaceOrientation has 5 possible values.

Objective-C

Swift

 

You need to handle the other 2 values (FaceUp and FaceDown) explicitly when using UIDeviceOrientation when handling rotations. This will be discussed in the 3rd section, “How to handle UIDeviceOrientation values”.

 

How to get UIDeviceOrientation values and updates

 
You can get the current device orientation using

Before using the above API to get orientation data, you must enable data delivery using the beginGeneratingDeviceOrientationNotifications method of the UIDevice. This method starts the accelerometer, so when you no longer need to track the device orientation, you must call the endGeneratingDeviceOrientationNotifications method to disable the delivery of notifications as well as the accelerometer. As a safety precaution, you can check if the app is generating UIDeviceOrientation change notifications using the isGeneratingDeviceOrientationNotifications method of the UIDevice. Also, if you want to be notified about the device orientation changes, you need to register for notifications for UIDeviceOrientationDidChangeNotification.

Objective-C

 

Swift

 

Important: You must always match your beginGeneratingDeviceOrientationNotifications call with an endGeneratingDeviceOrientationNotifications call!
In a personal iOS app I was working on before, I was calling beginGeneratingDeviceOrientationNotifications on iPad, but not on iPhone. Then on dealloc of that class, I was calling endGeneratingDeviceOrientationNotifications regardless if device is an iPad or an iPhone. I thought back then that this will not affect anything, and if not more, will ensure that the accelerometer gets shut down, if it gets mistakenly activated even on an iPhone. The result of this is that after the class has been deallocated, which means that endGeneratingDeviceOrientationNotifications has been called even if beginGeneratingDeviceOrientationNotifications was not, the rotation of all the screens in the app did not work anymore. A very tricky and not an obvious problem, so watch out for this.

 

How to handle UIDeviceOrientation values

 
If you want to use UIDeviceOrientation to rotate some of your views, then you need to ignore some of the UIDeviceOrientation values. Specifically, you need to ignore the Unknown, FaceUp, and FaceDown values. Luckily, the iOS SDK has the macro UIDeviceOrientationIsValidInterfaceOrientation which returns YES only if the specified UIDeviceOrientation is Portrait, PortraitUpsideDown, LandscapeLeft, and LandscapeRight.

Objective-C

 

Swift

 

Note that in effect, the last retrieved UIDeviceOrientation will be processed by your code. The possile flow of execution when using this code will look like this:

  1. User rotates the device to Landscape Left.
    The UIDeviceOrientation that you will get is LandscapeLeft. Since this is a valid UIDeviceOrientation for us, then we process this and rotate our view.
  2. User rotates the device to FaceUp (meaning device is on its back).
    Since you ignore FaceUp, nothing will be processed, so your views will stay in landscape.
  3. User rotates the device to Portrait.
    The UIDeviceOrientation that you will get is Portrait. Since this is a valid UIDeviceOrientation for us, then we process this and rotate our view.
  4. And so on.

 

Conclusion

Using UIDeviceOrientation may not be the best way to get the orientation of the views, but sometimes this is still needed. Following this guide should help you get started, and most of the time, this is all you will need. Just be sure to read through the important points. Drop by in the comments section if this post helped.

Happy Goals for iOS

Happy Goals for iOS

Want an app to help you track and achieve your goals, without the complex stuff, saving you from headaches? Checkout Happy Goals - Habits & Goals Tracker now in the App Store! Happy Goals has been featured in the App Store in over 32 countries. Start now, better late than never!

 

Thank you!

%d bloggers like this: