Reputation: 43
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
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
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 IBOutlet
s and flushing easily recreatable data.
Upvotes: 1
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