Getting autorotate right

You want most screens to autorotate when the user turns the phone.  But there can be some that just don’t work well in landscape (or in portrait).  You want to prevent those few screens from autorotating.

Currently in iOS 8 and later systems you can control this, but only on the top-most view controller.  So if you use a tab bar, or use navigation controllers, or any collection view type (page controller, etc), then the system controller for that collection view controller is asked about autorotation, but your dominant and selected view controller is not asked. Since we never write our code with nav controllers or tab bars this isn’t a problem right?

Snark aside, the description for the method supportedInterfaceOrientations says:

When the user changes the device orientation, the system calls this method on the root view controller or the topmost presented view controller that fills the window. If the view controller supports the new orientation, the window and view controller are rotated to the new orientation. This method is only called if the view controller’€™s shouldAutorotate method returns YES.

Of course the problem with this is that it violates the principle of putting the decision where the knowledge for that decision exists.

Here’s what I did to solve the problem.  I created  subclass of the UITabBarController (or whatever the top controller is) and added these following method overrides. (This code is in swift, but the Objective C code should be pretty obvious.)

    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask  {
        if let controller = selectedViewController  {
            return controller.supportedInterfaceOrientations()
        else {
            return return super.supportedInterfaceOrientations


    override func shouldAutorotate() -> Bool {
        if let controller = visibleViewController  {
            return controller.shouldAutorotate()
        else {
            return super.shouldAutorotate()

This delegates the decision to the responsible view and removes the decision from the container, which shouldn’t have to know this.

I also filed a radar bug #23677037  “Controlling autorotation is not pushed to the visible view controller”.

What do these methods do?

The work together.  The description I quoted above says that supportedInterfaceOrientation() is called if shouldAutorotate() returns true.  But my testing shows that if shouldAutorotate() doesn’t exist, then supportedInterfaceOrientation() will do the job by itself.  The iOS will tolerate one or the other missing and still work correctly it seems.

However, I plan to use both.  My testing wasn’t exhaustive and docs say to use both.  It’s easy to err on the side of caution in this case.

Consistent versioning in iOS projects

You start off with a version number on you app’s splash screen.  Then, perhaps later you add a Setting bundle and want a version there.  At some point you realize your logging would be more useful if it had a logged the version info when the app started up.  Now you need something to keep this all in and avoid confusing bugs where the version shows as one thing in one place, but a different version elsewhere.  And you want to be able to easily update it and use different types of version numbers in different places.

I got fed up with this and created a auto versioning script for Xcode for use in iOS and OS X projects.  It’s available on github and is called Auto Version Xcode.

It’s run early at build time, the readme has the install/use information.  It creates a version.h for Objective C or version.swift for Swift that can be used to define a number of build-time constants to be used in your app for logging or other purposes.  For example, the versions are:

let FullVersion = “1.0.0d6-1-F3380-dirty”

let Version = “1.0.0d6”

let SimpleVersion = “1.0.0”

The version is set in the project’s plist file and can be easily set in the project’s General tab.  In the above case, I set “1.0.0d6” and the script generated the above.

This script also has project environmental information like SDK name, Xcode version, and deployment target.  It also has the application name and configuration (release or debug).  You can use it to handle copyright name and year too if you like.

This has been handy to help me in my projects, I hope it’s useful for you.