8

I found a small behavior change between 7.1 and 8 on the UIViewController shouldAutorotate method. The Apple View Controller Programming Guide states that This method is called before performing any autorotation.

However I noticed that when I simply disable shouldAutorotate (return NO), the method is called on Portrait -> Landscape rotation, but not on the following Landscape -> Portrait rotation. Again the method should always be called as I understand it. This occurs when running on iOS 8, but not on iOS 7.1.

This seems related to a new method in the call stack in iOS8 :

[UIWindow shouldAutorotateToInterfaceOrientation:checkForDismissal:isRotationDisabled]

I could not find Is there any description of this method and its behavior, any idea where I could find more information about this internal method ?

Simple steps to reproduce this:

  1. Create a new Single View Application project in Xcode
  2. Update your ViewController.m to implement shouldAutorotate

    - (BOOL)shouldAutorotate
    {
        UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
        NSLog(@"%s orientation is %@", __PRETTY_FUNCTION__, [self stringFromDeviceOrientation:orientation]);
        // Disable autorotation of the interface.
        return NO;
    }
    
    - (NSString *) stringFromDeviceOrientation:(UIDeviceOrientation)uido
    {
        NSString *orientation = @"UIDeviceOrientationUnknown";
        switch (uido) {
            case UIDeviceOrientationPortrait:
                orientation = @"Portrait";
                break;
            case UIDeviceOrientationPortraitUpsideDown:
                orientation = @"PortraitUpsideDown";
                break;
            case UIDeviceOrientationLandscapeRight:
                orientation = @"LandscapeRight";
                break;
            case UIDeviceOrientationLandscapeLeft:
                orientation = @"LandscapeLeft";
                break;
            case UIDeviceOrientationFaceDown:
                orientation = @"FaceDown";
                break;
            case UIDeviceOrientationFaceUp:
                orientation = @"FaceUp";
                break; 
                default:
                    break;
            }
            return orientation;
        }
    
  3. Run on simulator iPhone 5s (7.1) : shouldAutorotate is called when switching to Landscape and back to Portrait

  4. Run on simulator iPhone 5s (8.0) or iPhone 6 : shouldAutorotate is called when switching to Landscape but it is not called when switching back to Portrait.

1 Answer 1

9

Same thing was happening to me. I have a feeling there is a bug in iOS8 because my same code worked fine in iOS7. Also just as a user I was have a lot of rotate problems in the apps I use. In 8 shouldAutorotate calls when you rotate to the side but then not again when you return to a normal rotation. That is unless it actually did an autorotation to the side, in which case on the return it is called.

So it's because your `shouldAutorotate' is always returning 'NO'. My assumption is that for some reason in iOS8 they (the apple coders who changed this behavior) decided that if they got a NO when rotating to the side, they don't need to call shouldAutorotate when rotating back to portrait. So it broke the behavior that we were expecting.

No one is talking about it or complaining. Google returns almost no results for this exact scenario. I think that's because in order for this to happen you have to be trying to use 'shouldAutorotate' as a device rotation notification but NOT actually be using the OS's auto rotation features. For example, I do opengl games. So I just this to let my engine know to rotate the game graphics. But I'm not rotating my view. I don't think many people were using this for device rotation notifications.

So I decided to use device notifications instead. In my view controller:

- (void) movingToBackground: (NSNotification *) notification {
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}

- (void) movingToForeground: (NSNotification *) notification {
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
}

And to receive the messages:

   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewChanging:) name:UIDeviceOrientationDidChangeNotification object:nil];

And the method:

- (void)viewChanging:(NSNotification*)notification
{
   NSLog(@"View is changing");
   previousOrientation = orientation;
   orientation = [[UIDevice currentDevice] orientation];

   if (previousOrientation==orientation && forceReorientation==NO) {
       return;
   }
   ... do stuff ...

And then back in my view controller I turned all auto rotation stuff to NO.

4
  • 1
    I agree with your analysis, the method on the way back is not called probably due to this new shouldAutorotateToInterfaceOrientation and its isRotationDisabled flag. Your workaround (using Notifications) is the proper way, and there is no guarantee that autorotation code will be called, especially now that iOs 8 handles rotations as size changes. I'll wait a bit before accepting your answer, in case more info comes up.
    – lazi74
    Nov 24, 2014 at 9:24
  • 1
    thanks. btw i'm using the above code now in my apps and it appears to be working. My only worry was that beginGeneratingDeviceOrientationNotifications might cause too many notifications with every slight rotation even if it's not a full 90 degrees. But I'm not seeing the "View is changing" print except on actual device rotations. So I think it's good.
    – badweasel
    Dec 8, 2014 at 7:31
  • Are you having the solution? I make wonderful rotation control of the status bar. And yet achieved an accelerometer-coordinated url protocol navigation from another app or return from another orientation. But, sadly, stopped on the step where on-screen keyboard should rotate accordingly. In my solution, I have (as you too) a fixed portrait-oriented view with its OpenGL layer. How to force iOS to NOT animate its horrous rotation??? :-) Jan 10, 2015 at 13:15
  • I'm not totally sure I follow. But the keyboard solution is to force the UI to be upright when they're entering input from the keyboard. It's totally ok to force the user to rotate the phone for some things. In an OpenGL game it wouldn't be very often that they use the keyboard.
    – badweasel
    Jan 10, 2015 at 19:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.