How would I detect the orientation of the device on iOS 9?

Before iOS 9 the device orientation could be detected using statusBarOrientation, however the "UIApplication Class Reference - Prerelease" and "Xcode 7 beta 4" is showing this property was deprecated for iOS 9.


I am confused because at "UIApplication Class Reference - Prerelease", the statusBarOrientation is shown as deprecated but also is refering to see also statusBarOrientation, what is the new way to get the device orientation?

Replies

The preferred way is to use size classes and the size of your view, not the device orientation (which may not be the same as the user interface orientation anyway). Think about the new larger iPad about which rumours have been flying... imagine a vertical split screen where the device is in portrait but it shows two apps stacked vertically in landscape, or multiple apps tiled or something... the writing is on the wall that your app should be ready to be displayed in a rectangle of any size and shape. I am just speculating of course but Apple has been pushing us in that direction.

Following up on junkpile's explaination, here is the preliminary documentation describing how to design for multiple size classes:


https://developer.apple.com/library/prerelease/ios/recipes/xcode_help-IB_adaptive_sizes/chapters/AboutAdaptiveSizeDesign.html

In general, one of the hallmarks of a (assumed in this case) well-designed API is that it is isolated from as many outside variables as possible. If you give it some input values, you get out some output values, regardless of device or orientation (etc.).


However, there are times when these factors become necessary to consider. So (just checking)...is there some additional technical reason/error when testing, that you're asking about or are you just being pro-active towards a/that deprecation? In other words...if you ignore the deprecation (for now), what happens?

Reading the status bar orientation is not deprecated, only writing to it is. This may have been an error in how we constructed the header if you are seeing this on the getter.

This is the method I use to get device orientation:


/
    func deviceOrientation() -> String! {
        let device = UIDevice.currentDevice()
        if device.generatesDeviceOrientationNotifications {
            device.beginGeneratingDeviceOrientationNotifications()
            var deviceOrientation: String
            let deviceOrientationRaw = device.orientation.rawValue
            switch deviceOrientationRaw {
            case 1:
                deviceOrientation = "Portrait"
            case 2:
                deviceOrientation = "Upside Down"
            case 3:
                deviceOrientation = "Landscape Right"
            case 4:
                deviceOrientation = "Landscape Left"
            case 5:
                deviceOrientation = "Camera Facing Down"
            case 6:
                deviceOrientation = "Camera Facing Up"
            default:
                deviceOrientation = "Unknown"
            }
            return deviceOrientation
        } else {
            return nil
        }
    }


If you print the orientation right away as you start an application, it will return "Unknown", but if you recursively update this method as the application runs (or print it well after the application has started), it will return the correct value.

I solved the issue like this:


import UIKit

extension UIScreen {

  func isPortrait() -> Bool {

    return self.bounds.width < self.bounds.height
  }
}

class BaseViewController: UIViewController {

  private lazy var _isPortrait: Bool = UIScreen.mainScreen().isPortrait()

  func isPortrait() -> Bool {

    if let parentViewController = self.parentViewController as? BaseViewController {

      return parentViewController.isPortrait()
    }

    return _isPortrait
  }

  override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    if let superView = self.view.superview {

      if superView.isKindOfClass(UIWindow.self) && self.parentViewController == nil {

       _isPortrait = size.width < size.height
      }
    }

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
  }
}


At least I assume that the child viewController will never touch inherited private _isPortrait, because it is lazy. Only the top level view can of the rootViewController is allowed to set this property. The super viewWillTransitionToSize function is called after the check is done. So if the value was set on the rootViewController, all child viewController will have the correct value at the time their viewWillTransitionToSize function is called. This has to be done, because you can not rely on the the size of the child viewController views, but at least you can trust your rootViewController if it is fullscreen. 😉 Hope that will help someone somehow.