objective-ciosmemory-warning

Prevent instance variables from being cleared on memory warning


I've got a relatively simple problem that's been evading solution for some time. I have a view controller and an associated XIB. The view controller is called FooterViewController. FooterViewController's view is set as the footer view of a tableview.

FooterViewController's view includes a label for showing feedback to the user. I would like this label to persist until its value is changed by my application. Under normal circumstances, it does. However, I've just begun testing with memory warnings, and I've found that after the view is unloaded in response to a memory warning, the label is cleared.

Here's what I've tried so far to solve the problem: in FooterViewController's viewWillUnload method, I store the label's text in an instance variable called statusString:

- (void)viewWillUnload
{
    statusString = [statusLabel text];
    testInt = 5;
    NSLog(@"View will unload; status string = %@; testInt = %d", 
            statusString, testInt);

    [super viewWillUnload];
}

Note that I've also set another instance variable, declared as NSInteger testInt, to 5.

Then, in FooterViewController's viewDidLoad method, I try to set the label's text to statusString:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"Just before setting label, statusString: %@; testInt: %d", 
            statusString, testInt);
    [statusLabel setText:statusString];
    NSLog(@"View did load.");
}

However, this does not work. Further, in the log after simulating a memory warning, I see:

View will unload; status string = Invalid IP address Error code: 113; testInt = 5

(Note that "Invalid IP address Error code: 113" is the correct value for statusString)

Then, after navigating to FooterViewController again, I see:

Just before setting label, statusString: (null); testInt: 0

This indicates to me that for some reason, the instance variables of FooterViewController are being reinitialized when the view loads again. A final note: the method initWithNibName:bundle: is being called each time the view must reload, though I expect this; after all, the view must be reloaded from the NIB.

So, my questions are these:

  1. Why do these instance variables appear to be nullified or zeroed in the process of unloading and reloading the view?
  2. If I'm doing something incorrectly that's causing this nullification, what is it?
  3. If I'm not doing anything incorrectly, and this is normal behavior, how should I handle maintaining state between loads of the view?

Thanks, Riley


Solution

  • I figured out what was going on, finally. The issue was that I called the allocation and initialization methods for FooterViewController in its parent view controller's viewDidLoad method. When the views were dumped and subsequently reloaded, my view controller was re-initialized! This destroyed the original FooterViewController, which maintained the instance variables I needed, and replaced it with a brand-new VC.

    The solution was to move [[FooterViewController alloc] init] to the init method of FooterViewController's parent VC, so that the initialization was only performed once per run cycle.

    I've learned my lesson: don't reinitialize your view controllers unless you really mean to do so. As such, be very careful where you put your calls to the initializer in parent view controllers.

    Thanks for the help I got from the two answerers.