iOS 6 Autorotation Problems and Help

So iOS6 has launched and many who have existing app in production which have the ability to autorotate will need to upgrade to iOS6 eventually and if they are like me they may run into issues when converting converting over to the new SDK.

What has changed

iOS asks the app whether or not it can autorotate and what are the supported orientations. These orientations are generally declared in your info.plist and for every viewController which you would like to allow to rotate you would simply override - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation and return YES or whatever specific orientations you wish to support. What is important is the current view controller is dictating whether or not the app rotates. In iOS6 this is reversed and the app determines whether or not an app can rotate by asking the navigation hierarchy in the reverse order. This happens by asking first the highest level on the navigation chain and whenever it gets the answer it needs it will use it. I will explain what I mean below.

The basics in code:

- (BOOL) shouldAutorotateToInterfaceOrientation: is now deprecated for iOS6 or later.

- (NSUInteger) application:supportedInterfaceOrientationsForWindow: is now put in the app delegate to declare the orientations for the window

- (BOOL) shouldAutorotate is now asked at the time of autorotation for a viewController or subclass

- (NSUInteger)supportedInterfaceOrientations is now used to return a mask representing the allowed orientations a viewController or subclass

Consider the example of an app with the navigation structure below:

[app delegate]

——-> [NavigationController]

——–> [ViewController]

——–> [ViewController]

 

Assume you wanted to allow autorotation for all views in your app.

iOS5 and older: You would traditionally override shouldAutorotateToInterfaceOrientation in each of your viewControllers and return YES to allow autorotation for both.
iOS6: In iOS6 we now subclass the NavigationController override - (NSUInteger)supportedInterfaceOrientations to return all orientations and override - (BOOL) shouldAutorotate to return YES. this will return support for all orientations and the individual viewControllers will not be consulted.

Assume you wanted to allow orientation only for the second ViewController

iOS5 and older: You would override shouldAutorotateToInterfaceOrientation in each viewController and return YES for the one which you allow autorotation and NO for the one you don’t.

iOS6: In this case you would still override the NavigationController but rather than returning YES for shouldAutorotate you must consult your current ViewController. So you would override each viewController’s shouldAutorotate and return the appropriate value while in the NavigationController you would return your current viewControllers’s shouldAutorotate result.

Your ViewControllers

- (BOOL)shouldAutorotate
{
return YES; // Or no
}

Your navigation controller
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate; //you are asking your current controller what it should do
}

-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}

What is important is to understand the basics of what is happening. For the above example the Navigation Controller is the parent and iOS always asks it what to do. If the entire app is allowed to autorotate or not you can simply return the answer at that level. If app contains views that will have different rules of autorotation then the navigation will have to ask the individual viewControllers for their result to be returned.

What does it all mean and my opinion

My opinion on this change is that its annoying to do the change over because I didn’t expect it but I welcome the change and I feel its a much more organized way of handling autorotation within your project structure while potentially making less code for you to write and maintain. The big thing that this improves is that you have to be very intentional when making an app that has specific rules of autorotation and the logic can be much easier to understand.

Troubleshooting.

If you are having problems converting an existing project to iOS6 with autorotation ensure that you have these things covered:

  • Ensure your .plist contains the proper supported orientations but this should be the case if coming from a previous project
  • Ensure your app delegate overrides application:supportedInterfaceOrientationsForWindow: and returns all supported orientations for your app
  • within your applicationDidFinishLaunchingWithOptions function make sure you are setting your window’s rootViewController and not just adding its subview to the window
  • Ensure you subclass all items in the Navigation hierarchy and override the new autorotation methods. This includes (tabBarControllers, NavigationControllers, ViewControllers, etc)

I hope this helps anyone who has to do a conversion to get through it and most importantly understand the new structure of autororation.

-Ryan


If you found this post helpful you can support me by buying my bodyweight workout app! (5 star average ratings, #1 in the ipad app health and fitness app store for 2 weeks straight…):

You Are Your Own Gym

7 thoughts on “iOS 6 Autorotation Problems and Help

  1. sam

    I am struggling with ios6 autorotation still. I created simple test app in ios6, from stroyboard, I customized NavigationController-…>TableViewController1—->TableViewController2
    In NavController, autoRotate = NO
    In TVC1, autorotate = YES
    In TVC2, autorotate = NO;

    autoRotate in NavController gets called, but not in the child TableViewControllers. It seems to ignore them. Any ideas?

    Reply
    1. admin Post author

      Yes this is expected and what I said above. If your NavController is called and you return NO then it takes that as the answer and doesn’t ask either of the TableViewControllers. What you need to do is ask the TableViewControllers from the navigation controller.

      Rather than returning NO in your NavController you should return “self.topViewController.shouldAutorotate;” What this will do is ask your current viewcontroller and it will then call their function and get their return value. I hope that makes sense

      Reply
  2. Chad

    This guy. This guy right here. I would write you a fucking sonnet if I didn’t hate writing sonnets.

    I just started doing iOS work (I’m an android guy) and for the life of me I couldn’t figure out why my shouldAutoRotate functions were not being hit. Probably the release of iOS6 was a bad time to start learning. I crawled over the place and it seems like very few people no what’s going on with the auto rotate issues. Your post is extremely well-written and the examples are awesome. You kick ass.

    Just wanted to let you know that your post was extremely valuable to me. I do have a couple questions though (keep in mind I’m an iOS n00b).

    Why did apple reverse the auto rotate hierarchy? Why the fuck would the root controller be the best dude to ask?

    I’ve read that subclassing the navigation controller is seen as a no-no. Is this going to change? Do you have any other ideas or is this the most clean?

    Godspeed you goddamn wizard

    Reply
  3. admin Post author

    I do not like subclassing the navigation controller but it is the solution that I found to be the most accepted in the developer forums when this problem came up. Its really not that big of a deal and you are only overwriting 2 functions in it.

    I think they reversed the order of rotate hierarchy because they are forcing the developers to make a more clean code structure for this. In general the autorotate code I’ve seen is pretty ugly and if you have a big app that you want to autorotate on every view you end up having to override that function in each View Controller. With this change in functionality with iOS6 you would simply return YES at the top level and not have to write anything else. Also if you do have logic where individual views need to autorotate in different ways you are forced to be very intentional with how you write your code and in general probably make better code. These are just my opinions and my hunch of why they did it.

    Reply
  4. Prakash

    I have made all the changes as advised but it is not working. One thing is strange, on my navigation controller I am returning a NO from shouldAutorotate method, but still views under it are auto rotating.

    Reply
  5. admin Post author

    @Prakash – I would make sure your shouldAutorotate is being fired by putting a breakpoint there. I would imagine it isn’t and that a step was missed along the way. An easy one to miss is if you are not setting the rootViewController in you “applicationDidFinishLaunchingWithOptions” method.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *


* 6 = twelve

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>