iOS 6 shouldAutorotate: is NOT being called

48,757

Solution 1

See if you are getting the following error when your App starts.

Application windows are expected to have a root view controller at the end of application launch

If so the way to fix it is by making the following change in the AppDelegate.m file (although there seem to be a number of answers how to fix this):

// Replace
[self.window addSubview:[navigationController view]];  //OLD

// With
[self.window setRootViewController:navigationController];  //NEW

After this shouldAutoRotate should be correctly called.

Solution 2

When using UINavigationController as the basis for an app I use the following subclass to give me the flexibility to allow the top most child viewcontroller to decide about rotation.

@interface RotationAwareNavigationController : UINavigationController

@end

@implementation RotationAwareNavigationController

-(NSUInteger)supportedInterfaceOrientations {
    UIViewController *top = self.topViewController;
    return top.supportedInterfaceOrientations;
}

-(BOOL)shouldAutorotate {
    UIViewController *top = self.topViewController;
    return [top shouldAutorotate];
}

@end

Solution 3

That method is not the correct way to determine that. The correct method is willRotateToInterfaceOrientation:duration:

The should rotate to orientation (as opposed to shouldAutorotate) method is deprecated and will no longer be called as of iOS 6, but it was not meant to be used the way you were using it anyway.

EDIT Response to repeated downvotes. Please explain why using the method I indicated is not an (to quote OP) "indication that a rotation is about to occur." The content of the question and the title are mismatched.

Solution 4

It looks that on iOS 6 the container navigations controller doesn't consult child view controllers when rotating:

in iOS 6 release notes :

Now, iOS containers (such as UINavigationController) do not consult their children to determine whether they should autorotate. By default, an app and a view controller’s supported interface orientations are set to UIInterfaceOrientationMaskAll for the iPad idiom and UIInterfaceOrientationMaskAllButUpsideDown for the iPhone idiom.

This behavior is easy to test. What I did is to use the same custom view controller

  1. first case as a main view controller
  2. second case as a child of a UIPageViewController

In the first case everything is decided in the custom navigation controller by the combination of shouldAutorotate and supportedInterfaceOrientations given that supportedInterfaceOrientations agrees with the supported orientations of the application.

In the second case even if the supportedInterfaceOrientations of the custom view controller is called by the UIPageViewController the return value is not taken in to consideration. It works if the two methods are overwritten in a subclass of the UIPageViewController. I am not sure about the side effects of that as this class is not supposed to be subclassed.

Solution 5

If your viewController is a child viewController in a UINavigationController then you can do the following:

  • Subclass UINavigationController
  • override shouldAutoRotate in your subclass
  • send your topViewController this message when this method get called

// This Method is inside your UINavigationController subclass

- (BOOL)shouldAutorotate
{
    if([self.topViewController respondsToSelector:@selector(shouldAutorotate)])
    {
        return [self.topViewController shouldAutorotate];
    }
    return NO;
}
  • Now your viewControllers will respond respectively to this method.
  • Note, that you can do the same with other orinetaion-methods
Share:
48,757

Related videos on Youtube

Lizza
Author by

Lizza

Updated on April 24, 2020

Comments

  • Lizza
    Lizza about 4 years

    I have been scouring the internet for a solution to this but am finding nothing. I am trying to make my iOS 5 app iOS 6 compatible. I cannot get the orientation stuff to work right. I am unable to detect when a rotation is about to happen. Here is the code I am trying:

    - (BOOL)shouldAutorotate {
        return NO;
    }
    
    - (NSUInteger)supportedInterfaceOrientations {
        return UIInterfaceOrientationMaskPortrait;
    }
    // pre-iOS 6 support
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
        return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
    }
    

    The new supportedInterfaceOrientation: method gets called just fine. The shouldAutorotate method, however, will not fire. I need to do some image swapping on rotate, but I can't get any indication that a rotation is about to occur.

    Thanks in advance.

    • KarenAnne
      KarenAnne over 11 years
      This is answered in here: stackoverflow.com/questions/12260261/… See it :D
    • Daniel J
      Daniel J over 8 years
      @KarenAnne, that answer doesn't fix the issue of 'shouldAutorotate' not being called in the first place. Also, 'shouldAutorotateToInterfaceOrientation' is deprecated in iOS 6, so it shouldn't be considered a valid option going foward.
  • Daniel Wood
    Daniel Wood over 11 years
    -(BOOL)shouldRotate has appeared in iOS 6, however, it is never called. How is one meant to have a view controller that rotates only some of the time now (for instance having a lock button to protect against rotations)?
  • Daniel Wood
    Daniel Wood over 11 years
    I figured out why my shouldAutorotate was not getting called in iOS 6. It was due to my view controller being a child of a UINavigationController and it appears that the nav controller doesn't delegate the -shouldAutorotate method to it's topViewController like the previous behaviour. You can get around this by subclassing the UINavigationController and overriding the -shouldAutorotate and -supportedIntervalOrientations methods.
  • borrrden
    borrrden over 11 years
    Yeah, it's a new way of doing things...only presented and root view controllers get the calls. The reasoning is that child view controllers usually just resize to fit the frames of their parents anyway. However, the wilRotate and didRotate methods are forwarded to child controllers by default.
  • possen
    possen over 11 years
    Subclassing UINavigationController is not recommended. A category is better see stackoverflow.com/questions/12520030/…
  • borrrden
    borrrden over 11 years
    @possen Out of curiousity, why do you say that? To me it seems like a category would be a stranger choice since it will delete an existing implementation and make it unreachable (compiler warning will be produced)
  • Mike M
    Mike M over 11 years
    There's a thread on the Apple forums where the Apple rep explicitly recommends against making a category, but subclassing instead. devforums.apple.com/message/744384
  • Dejell
    Dejell over 11 years
    WEll it doesn't work for me for UIImagePickerController. I tried to extend it (as it extends UINavigationController) and implement the method supportedIntervalOrientation and shouldAutoRotate but it wouldn't help
  • yoninja
    yoninja over 11 years
    I think this should be accepted as the correct answer. I had the same problem before but was able to fix it by doing something like this: self.window.rootViewController = navigationController; (which is the same as @user1672376's answer)
  • ashish
    ashish about 11 years
    yes I was trying hard to get shouldAutoRotate method to call but it was not working as soon as I changed the above piece of code it worked perfectly. This is the correct answer I was searching it lot.
  • Guilherme Torres Castro
    Guilherme Torres Castro about 11 years
    This answer is completely wrong, shouldAutorate is not deprecated, In fact it's only available on IOS 6.0 and it's the correct way to determine if the screen should or not rotate. the willRotateToInterfaceOrientation:duration: yes called when the screen will be rotate, not do determine if should or not rotate.
  • borrrden
    borrrden about 11 years
    This answer looks like it has been edited since I answered...I believe before it only had the old version of shouldRotate (shouldAutorotateToInterfaceOrientation). But my answer is still not "completely wrong" because OP is looking for (in his words) "detect when a rotation is about to happen". That is exactly what the willRotate method is for.
  • iEngineer
    iEngineer about 11 years
    Great.. it saved my time.. ;-)
  • Mausimo
    Mausimo about 11 years
    Solved my issue also. IMO this answer should be selected.
  • Bill Cheswick
    Bill Cheswick almost 11 years
    No, viewDIDLoad is too early: the VC doesn't know about its views yet. Do it in viewWillAppear, when self.view knows its current frame.
  • rudifa
    rudifa over 10 years
    Spot on, your answer saved my day.
  • Gallonallen
    Gallonallen over 10 years
    This is by far the easiest and most elegant solution to allowing each ViewController in a NavigationController to have their own supported interface orientations.
  • vincentjames501
    vincentjames501 about 10 years
    This is indeed a great solution and can be used with SplitViewControllers as well with a little tweaking.
  • Devang Vyas
    Devang Vyas about 10 years
    save my day (and night too)...Thanks!
  • tedyyu
    tedyyu almost 10 years
    To be more clear, create such a sub-class and then set it as the custom class for your navigation controller in storyboard Identity Inspector.
  • Daniel J
    Daniel J over 8 years
    But if you're not getting that error, and neither do you want to set some random UIViewController as the root view controller...
  • Patrick Domegan
    Patrick Domegan over 7 years
    Great answer thanks! Return type of supportedInterfaceOrientations should be changed from NSUInteger to UIInterfaceOrientationMask to remove a warning.
  • Patrick Domegan
    Patrick Domegan over 7 years
    Note: for this to work on iPad, you need to opt out of multitasking: <stackoverflow.com/a/31771093/341994>