shouldAutorotateToInterfaceOrientation not being called in iOS 6

ios, ios6, orientation

Solution

PLEASE READ this CAREFULLY or you could loose 1-2 days of your life with going nuts and fighting, shaking, turning your test device like the chimp in the zoo which grabbed a visitor's mobile! Sooner or later...promise :)

IN iOS 6

shouldAutorotateToInterfaceOrientation:

is deprecated and replaced by

shouldAutorotate

it means iOS 6 will never call `shouldAutorotateToInterfaceOrientation`:

so if you used the following in your application

BEFORE iOS6 (iOS5,iOS4 etc.)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode

}

return YES;
}

you should use

AFTER iOS 6+

- (BOOL)shouldAutorotate {

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

if (orientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode

}

return YES;
}

BE AWARE

`UIInterfaceOrientation` is a property of `UIApplication` and only contains 4 possibilities which correspond to the orientation of the status bar:

UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,

UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,

UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,

UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft

DO NOT CONFUSE IT WITH

`UIDeviceOrientation` which is a property of the `UIDevice` class, and contains 7 possible values:

UIDeviceOrientationUnknown - Can not be determined

UIDeviceOrientationPortrait - Home button facing down

UIDeviceOrientationPortraitUpsideDown - Home button facing up

UIDeviceOrientationLandscapeLeft - Home button facing right

UIDeviceOrientationLandscapeRight - Home button facing left

UIDeviceOrientationFaceUp - Device is flat, with screen facing up

UIDeviceOrientationFaceDown - Device is flat, with screen facing down

even you can theoretically use `UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];` which returns `UIDeviceOrientation` - the device actual orientation - BUT you have to know that `UIDeviceOrientation` is not always equal `UIInterfaceOrientation`!!! For example, when your device is on a plain table you can receive unexpected value.

You can use `UIInterfaceOrientation orientation = self.interfaceOrientation;` too which returns `UIInterfaceOrientation`, the current orientation of the interface, BUT it's a property of `UIViewController`, so you can access to this one only in `UIViewController` classes.

If you'd like to support both prior iOS6 (iOS3/4/5) and iOS6 devices - which could be evident - just use both `shouldAutorotateToInterfaceOrientation:` and `shouldAutorotate` in your code.

From iOS 6 there are 3 levels and 3 steps which the device checks during app launch, which you have to control if you'd like.

1. Info.plist - Supported Interface Orientations

which you could set graphically in the Summary tab. The sequence of allowed orientations is IMPORTANT, which you can change manually by editing the `info.plist`, and the device will choose the first when the app is launching! This is critical as the problem always the launch of the app when there is the chance that the `[UIDevice currentDevice].orientation` is unknown, especially when we test our app on a flat surface.

BE AWARE There is two other settings possibility with (iPad) or (iPhone) extension, if you use any of them, it will use that setting of the current device or simulator and neglect the general settings without the extension. So if you run an iPhone only app and accidentally you left a "Supported Interface Orientations (iPad)" line somewhere in the plist even without any data, it will neglect the rules you have established earlier in the general settings (in my example for iPhone) and you could get a rejection for your App with a text "We found that your app did not meet the requirements for running on iPad..." even if your app doesn't intend to use a given orientation on iPhone, but iPad will use it which could cause unpredicted errors, as all iPhone apps have to run on iPad too during the submission process.

2. AppDelegate - application:supportedInterfaceOrientationsForWindow

returning a bit mask listing of every orientations you'd like to permit, which override the info.plist settings.This is called at least once every times the device rotates.

3. Top-level view controller or RootViewController - supportedInterfaceOrientations

which gives an intersection with the set of the app and app delegate, which has to have a non zero result to avoid crash. This is called at least once every times the device rotates, except there is an another method installed in our controller:

shouldAutorotate

which interferes with the app's permitted orientations, and gives a `BOOL` with default `YES`.

BE CAREFUL when you use `NavigationController`

as the topmost controller in your `AppDelegate`, like this:

DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:detailViewController];
self.window.rootViewController =nil;
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;

in this case you have to place the following code in your `AppDelegate` as a category attachment to `NavigationController` class, as this is the topmost controller, and if you haven't made a subcategory of it, you have no place/code where you can set its orientation settings, so you need to force it to check your real `rootViewController` in this case the `detailViewController` for the orientations:

@implementation UINavigationController (OrientationSettings_IOS6)

-(BOOL)shouldAutorotate {
return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations {
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

after this you can set the preferred orientations in your "topmost" `ViewController` (in my example this is the `detailViewController`) with any of the methods you have available in iOS 6 for `ViewControllers`, as below:

1. (BOOL)shouldAutorotate

2. (NSUInteger)supportedInterfaceOrientations

3. (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation

Problem

I'm using MGSplitViewController and I'm using`shouldAutorotateToInterfaceOrientation` to control the size of the master view controller on rotation. It's all working fine on iOS 5 but on iOS 6 (both simulator and iPad) `shouldAutorotateToInterfaceOrientation` is never called. Is this a bug that I should expect to be fixed with the final release of iOS 6 or something that I'm not aware of has changed?

Original source

Related problems