Strange problem with device rotation on iPad

Discussion in 'iOS Programming' started by Duncan C, Nov 20, 2013.

  1. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #1
    I have a bizarre problem with an app I'm developing for a client.

    It's a universal app, and it was originally targeted at iOS >=6. The client has since decided to add iOS 7 only features, so we've updated it to use a base SDK and deployment target of iOS 7. It is a storyboard based app using struts and springs rather than auto-layout.

    At the client's request, the app did use a custom title bar under iOS 6 that was made to look like, but was not, a navigation bar. The client has since requested that the app be refactored to use an actual iOS 7 navigation bar. So, I refactored it to embed the initial view controller in a navigation controller, and refactored all the custom code to create a navigation-bar-looking interface to an actual navigation controller and navigation bar. The client wants a custom cross-fade transition instead of the standard push transition, so I subclassed UINavigationController and implemented custom versions of pushViewController:animated: and popViewControllerAnimated: that call the superclass's implementation of those methods from inside a UIView transitionFromView:toView:duration:eek:ptions:completion: method.

    The app does not use segues to transition between VCs in the storyboard. Instead, it instantiates each view controller using instantiateViewControllerWithIdentifier and then pushing the view controller onto the navigation controller. That is for good design reasons that would take a LOOOONG post to explain, but trust me, it's for sound design reasons.

    Anyway... I just noticed the other day that at some point the app no longer auto-rotates correctly on my development iPad 2, or on my partner's iPad 2 or iPad mini. It does auto-rotate correctly on the simulator.

    When I launch the app it comes up in the current device orientation correctly. When I then rotate, the status bar rotates to the new orientation, but the app contents (navigation bar and views) stay put. It's very bizarre.

    In order to rule out the custom navigation controller as the source of the problem, I switched the navigation controller back to a vanilla UINavigationController, and the problem persists.

    The app is set up to not allow device rotation when run on iPhone except on a few specific screens (that display full-screen images or videos.) Other than those screens, the app is portrait-only on iPhone/iPod touch. It auto-rotates correctly on those few screens that support landscape.

    I am at a loss as to what's causing this, or what to do to find and fix the problem. I'm not sure when it started happening, as I just noticed it. It's very strange to have the status bar rotate to a different orientation than the app UI.

    Has anybody else seen the same problem, and more importantly, found a solution to it?


    Regards,

    Duncan Champney
     
  2. Duncan C thread starter macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #2
    Found it, and it's a weird one.

    I also posted this question to the Apple boards. I'll also post the solution here:

    Mystery solved. It's a weird one.

    We were adding support for iBeacons to the app, and we start up our region monitoring in a class's +initialize method. If region monitoring fails, we display a UIAlertView.

    As it turns out, we display the UIAlertView before the app's UI has been set up. That is what triggers the problem.

    This looks like an OS bug to me. If displaying an alert before the UI is set up is invalid, it should throw an exception. Instead, the alert displays (and appears on top of the app's root view controller) but after that, auto-rotation is broken for the life of the app.

    For now, I've simply refactored the code that displays the alert to display it after a pause. (with GCD code similar to performSelector:withObject:afterDelay: ) That way, the app's UI is initialized by the time the code to display the alert is invoked.

    I've submitted a radar bug on this with a mimum app that recreates the problem.

     
  3. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #3
    Why don't you change the point where this check happens to later in the startup sequence of the app. Using a pause like that is likely to break sometime.
     
  4. Duncan C thread starter macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #4
    I doubt it. The problem is that the alert is displayed before the UI is initialized. Simply by returning to the event loop first, the UI initialization gets a chance to happen. I could likely use a delay of zero and it would still work.

    I want to initialize the beacon regions as early as possible so the app starts detecting beacons immediately.

    Another way to refactor the code would be to set a flag in a static variable if there is a problem starting Bluetooth, and then write code in the app's didFinishLaunching method that checks that flag and displays an error if Bluetooth failed to initialize.
     

Share This Page