views:

66

answers:

2

At various points during my application's workflow, I need so show a view. That view is quite memory intensive, so I want it to be deallocated when it gets discarded by the user. So, I wrote the following code:

- (MyView *)myView {
    if (myView != nil)
        return myView;

    myView = [[UIView alloc] initWithFrame:CGRectZero]; // allocate memory if necessary.
    // further init here

    return myView;
}

- (void)discardView {
    [myView discard];   // the discard methods puts the view offscreen.
    [myView release];   // free memory!
}

- (void)showView {
    view = [self myView];
    // more code that puts the view onscreen.
}

Unfortunately, this methods only works the first time. Subsequent requests to put the view onscreen result in "message sent to deallocated instance" errors. Apparently, a deallocated instance isn't the same thing as nil. I thought about putting an additional line after [myView release] that reads myView = nil. However, that could result in errors (any calls to myView after that line would probably yield errors).

So, how can I solve this problem?

+4  A: 

Setting myView to nil is the correct thing to do here. Not doing so is what's yielding errors, because it undetectably refers to a deallocated object. Your code tests for nil to see if it needs to create a new view, so you should set the variable appropriately.

Chuck
+1  A: 

You're going to have problems because your not using accessors. You need to define a property for the view. Then whenever you refer to view use the self-dot notation. If you do this then simply setting the view property to nil like this:

self.myView=nil;

... will trigger its release automatically.

However, this is bad way to manage the view especially if you load it from nib. The view most likely is a required property of a controller object. Setting it to nil invites crashes.

The better way is to have the view controller handle memory issues. On the iPhone you can put memory management code in viewDidDisappear: or didReceiveMemoryWarning. In any case you don't kill the view as long as the controller is alive but instead release the memory intensive parts of the view e.g. images. This leaves the view as a lightweight shell object. Then in 'viewWillAppear` you load the memory intensive parts back in.

However, the best way to handle this problem is to actually pop the view controller from a navigation stack. At that point the view controller cleans up after itself automatically.

TechZen