2
votes

I have an iPhone view controller that's initialized with a XIB.

If a view controller's view is not visible when a memory warning comes through, it sets its view to nil (releasing it). But when an overlapping view is dismissed and the cleared-out view becomes visible again, Cocoa doesn't reload it from the XIB; it simply creates a blank one. This leaves a blank white screen, and a broken app.

The Apple doc for UIViewController's loadView method says, "If the view controller has an associated nib file, this method loads the view from the nib file. A view controller has an associated nib file if the nibName property returns a non-nil value." So I overrode loadView simply to check nibName after initializing the controller, and nibName is correct. So subsequent calls to loadView should be reloading from the XIB. I verified that loadView is called again after the memory warning.

UPDATE: With more testing and logging, I've determined that after the second viewDidLoad call, the view's IBOutlets are non-nil. Since I set them to nil in viewDidUnload, I conclude that the view was indeed reloaded from the XIB. So why is it showing up as an all-white screen?

Thanks for any insight.

Here's viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];

    _photoViewController = [[EGOSimplePhotoViewController alloc] initWithPhotoSource:_photoSource
                                                                      scrollView:bigImageScrollView
                                                                     enclosingView:photoSquare];
    _photoViewController.delegate = self;

    if(_progressHUD == nil)
    {
        if(self.navigationController.view != nil)
        {
            _progressHUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
        }
        else
        {
            _progressHUD = [[MBProgressHUD alloc] initWithView:self.view];
        }
    }

    // Add HUD to screen.
    if(self.navigationController.view != nil)
    {
        [self.navigationController.view addSubview:_progressHUD];
    }
    else
    {
        [self.view addSubview:_progressHUD];
    }

    [_progressHUD release];

    _progressHUD.labelText = @"Loading...";
    [_progressHUD show:YES];
}

And viewDidUnload:

- (void)viewDidUnload
{
    [_photoViewController release];
    [super viewDidUnload];
}
1
Did you implement viewDidUnload?Costique
Yes. The question is how to reload.Oscar
If you do it right, views are reloaded automatically. When the controller is about to appear, it detects that its view has been unloaded, and sends itself loadView. Please show us the code in loadView, viewDidLoad and viewDidUnload.Costique
Have you tried putting [super viewDidUnload] in your viewDidUnload? Did you override loadView? The system should absolutely be sending you loadView (and then viewDidLoad) if it has previously sent you viewDidUnload.rob mayoff
I didn't even have a viewDidUnload when this problem started, so that's not the problem (good catch though). The system IS sending me loadView. It just isn't loading from the XIB the second time.Oscar

1 Answers

1
votes

The viewControllers view loading mechanism after a memory warning is supposed to be transparent to the developer. you shouldn't have to do a thing to re-create the view.

For VCs loaded using nib, the system will re-create the view and viewDidLoad will be called. For VCs loaded programatically loadView will be called again.

and the whole cycle repeats until viewDidAppear: and you see the view again.

USE CASE:

UITabBarController (2 tabs assumed)

User on Tab 0 >> Goes to Tab 1 >> Triggers memory warning >> All active VCs on UITabbarController receive memory warning >> UITabBarController will unload view of Tab0 >> Tab0 receives viewDidUnload:

When user switches back to Tab 0 its view will be created from scratch beginning from loadView OR viewDidLoad as I said.

If you are not receiving these events then your viewController hierarchy is messed up. Maybe you just added some VCs view as subView to something OR maybe your VC is not connected to window either directly OR through some container controller (UINavigation, UITabBarController etc) OR maybe you tried rolling up you own containerController and messed up.

Try understand the UIViewController lifecycle from loadView to viewDidUnload and dealloc. Its awesome. It will help a lot in writing good code and design of your apps.