Michal
Michal

Reputation: 43

View controller / memory management

i'm a little bit confused with memory management in view controllers.

Lets say i have header file like this:

@interface MyController : UIViewController {
    NSMutableArray  *data;
}
@property (nonatomic, retain) NSMutableArray *data;
@end

and .m file looks like that:

@implementation MyController
@synthesize data;

- (void)dealloc
{
    [self.data release];
    [super dealloc];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    if (self.data == nil)
        self.data = [[NSMutableArray alloc] init];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    [self.data release];
    self.data = nil;
}

Is that ok from the correct memory management point of view? Will that work after dealloc via Memory Warning? How You do that in your apps?

Thanks for your answers ;)

Upvotes: 2

Views: 704

Answers (3)

Caleb
Caleb

Reputation: 125017

These lines from -viewDidUnload both release data:

[self.data release];
self.data = nil;

Since you're using the property setter in the second line, and data is a retained property, the setter will release data. This is an over-release, and it'll cause a crash either right away or later, depending on whether other objects also retain that object. To fix, simply delete the first line and rely on the setter to do the right thing.

The -dealloc method, on the other hand, shouldn't use the setter as it does now. You should change:

[self.data release];

to:

[data release];
data = nil;       // this line isn't strictly necessary, but often considered good form

The reasoning here is that it's conceivable that this class could be subclassed, and someone might override the property setter in such a way that it has some side effects that could cause problems when the object is being deallocated. You should access the ivar directly -- notice that I left off the "self." so that we're dealing with the ivar and not the property accessor. (-init and -dealloc are the only places where you have to worry about that; use the property accessors everywhere else.)

Upvotes: 1

Wayne Hartman
Wayne Hartman

Reputation: 18497

You are not guaranteed that viewDidUnload will ever get called. Unlike init/dealloc, which get called in pairs, viewDidUnload is undeterministically called. viewDidUnload is only called if there is a low memory situation and your view is not the active view.

Depending on how your model is created and the implications of it remaining in memory, it may make more sense for you not to get rid of it. An example of this may be that recreating that data may involve an expensive web service call. It therefore would be a bad user experience to have to wait for that data to get recreated. If it must absolutely go, a better strategy may be to cache the data to disk so that you can easily reconstruct it.

viewDidUnload should only contain cleaning up your IBOutlets and flushing easily recreatable data.

Upvotes: 1

Deepak Danduprolu
Deepak Danduprolu

Reputation: 44633

While the alloc-retain calls balance out in viewDidLoad and viewDidUnload and should prove no problem memory-wise, it would be cleaner to take ownership only once and relinquishing it once rather than twice.

- (void)viewDidLoad
{
    [super viewDidLoad];

    if (self.data == nil)
        self.data = [NSMutableArray array];
}

and

- (void)viewDidUnload
{
    [super viewDidUnload];

    self.data = nil;
}

Upvotes: 1

Related Questions