Why Doesn't iOS Autorotate a View loaded from a Nib after it was released by didReceiveMemoryWarning?
Asked Answered
P

2

5

My iPad app makes heavy use of autorotation. This is great. However, I've noticed that if a hidden view is released by the default implementation of didReceiveMemoryWarning (as described here), when the view is re-loaded from the nib and I happen to be in landscape, it loads it in portrait. This wreaks havoc with the interface until I rotate the iPad manually and force it to go to the proper orientation.

I had assumed that iOS would load the view in the current orientation; that's what it does when the app launches. But it no, not after being unloaded by didReceiveMemoryWarning. Why not? And how can I get it to do that?

Prajna answered 11/1, 2011 at 7:45 Comment(8)
Is the view outside of the view hierarchy (not a subview of the UIViewController view)?Castorena
@dbarker - Nope, in fact it's the main view of the app.Prajna
@dbarker Ah, but looking more carefully, I see that it's subviews of that view that are not properly rotated. Subviews included in the nib are properly rotated. Sort of. Hrm. Something might be up with my -willAnimateRotationToInterfaceOrientation:duration: method. Maybe it's not getting called because the rotation isn't animated?Prajna
Yes, neither -willRotateToInterfaceOrientation:duration: nor -willAnimateRotationToInterfaceOrientation:duration: gets called. They're both called on app launch…Prajna
Sounds right - the rotation callbacks won't get called when the view (re) loads. For the views that aren't managed by a nib, you'll need to adjust them manually to the orientation that UIViewController#interfaceOrientation returns. Not sure, but possible that this is what the nib does behind the scenes.Castorena
Hrm. In what method should I do that? It's already done automatically on launch, so I'd need to be able to tell whether or not the view is loading on launch.Prajna
That check should happen in viewDidLoad. If I'm understanding right, viewDidLoad is always orienting these views one way and the will/didRotate messages are correcting it (on launch) if it's wrong. Since there are cases where viewDidLoad happens and will/didRotate are not sent, viewDidLoad has to set these views up correctly for the current orientation. The will/didRotate messages will still handle further orientation changes.Castorena
Yeah, that's what I figured; see answer below. Kind of annoying, though. Thanks for the help!Prajna
P
4

The answer, determined thanks to pointers from dbarker, is that the view controller's rotation methods, including -willRotateToInterfaceOrientation:duration: and -willAnimateRotationToInterfaceOrientation:duration:, will not be called when a view is reloaded after a the default implementation of didReceiveMemoryWarning has unloaded the view. I've no idea why it would be different on app launch, but I do have a workaround

What I did was to set a boolean ivar, named unloadedByMemoryWarning, to YES in didReceiveMemoryWarning, like so:

- (void) didReceiveMemoryWarning {
    unloadedByMemoryWarning = YES;
    [super didReceiveMemoryWarning];
}

Then, in viewDidLoad, if that flag is true, I set it to NO and then call the rotation methods myself:

if (unloadedByMemoryWarning) {
    unloadedByMemoryWarning = NO;
    [self willRotateToInterfaceOrientation:self.interfaceOrientation duration:0];
    [self willAnimateRotationToInterfaceOrientation:self.interfaceOrientation duration:0];
    [self didRotateFromInterfaceOrientation:self.interfaceOrientation];
}

Kinda sucks that I have to do this, but it does work, and now I'm less concerned about getting killed by iOS for using too much memory.

Prajna answered 12/1, 2011 at 5:8 Comment(2)
I am facing the same issue in my iPad app. This is kind of weird behavior but your solution helped me.Tracy
Tried that solution but it's not doing it on my end unfortunately. Bleh... digs onTatum
E
1
  1. I think iOS 5 might fix this.

  2. For iOS 4.3, I've had good luck with another fix. After the load from nib:

    [parent.view addSubview:nibView];  
    nibView.frame = parent.view.frame;  
    [nibView setNeedsLayout];  
    

    If that worked, you could jettison the unloadedByMemoryWarning logic, since it's safe to do every load. Got the tip & code (basically) from here.

Ethnocentrism answered 5/1, 2012 at 14:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.