Memory leak after second viewing of tableview
I have two U开发者_如何学PythonITableViewControllers. I'm pushing to the second one and calling the following method in viewDidLoad.
The second time I dispose of this view and go back to the first view, I get a memory leak.
Instruments says the problem's on the last line of the following method.
- (void)fetchRecords {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Articulation" inManagedObjectContext:[self managedObjectContext]]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"articulationGroup == %@", selectedArticulationGroup];
[request setPredicate:predicate];
static NSArray *sortDescriptors = nil;
if (!sortDescriptors)
sortDescriptors = [[NSArray alloc] initWithObject:[[[NSSortDescriptor alloc] initWithKey:@"text" ascending:NO] autorelease]];
[request setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
if (!fetchResults)
NSLog(@"no fetch results ArticulationsViewController, error %@", error);
[request release];
self.articulationsArray = [NSMutableArray arrayWithArray:fetchResults];
}
I've got no idea... going to bed :'(
For one thing, you're leaking your sortDescriptors array if you take the allocation branch. <soapbox> I strongly recommend you use curly braces around all if/else blocks even if they only have one line - these bugs are very difficult to find after the fact</soapbox>
Please post your dealloc method and the ivar declarations.
Well, I notice two things which might be correct but I wanted to ask about anyway.
First of all, ur asking in the if statement: if (!fetchResults)
. That would mean fetchResults
possibly doesn't exist. Still, you try to initialize an array with that.
Secondly, I don't know how you allocated articulationsArray
, but does changing the line into self.articulationsArray = [[NSMutableArray alloc] initWithArray:fetchResults]]
have any effect?
Why is your sortDescriptors
array static? Typically, you would do something like this:
NSSortDescriptor *textSort = [[NSSortDescriptor alloc] initWithKey:@"text" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:textSort]];
[textSort release];
Also, after if (!fetchResults)
you shouldn't save your array, but do something like this:
if (!fetchResults)
{
NSLog(@"no fetch results ArticulationsViewController, error %@", error);
}
else
{
NSMutableArray *articulationsArray_tmp = [fetchResults mutableCopy];
self.articulationsArray = articulationsArray_tmp;
[articulationsArray_tmp release];
}
[request release];
Also note how you could set the articulationsArray
differently. One should always be careful with these NSMutableArray
s ... :)
This block is completely unnecessary and it is dangerous:
static NSArray *sortDescriptors = nil;
if (!sortDescriptors)
sortDescriptors = [[NSArray alloc] initWithObject:[[[NSSortDescriptor alloc] initWithKey:@"text" ascending:NO] autorelease]];
[request setSortDescriptors:sortDescriptors];
Any static object is dangerous to memory and you use them only in special cases. Why nail an array with only a local scope to a specific address/block? All this can be replaced with one line:
[request setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortWithKey:@"text" ascending:NO]]];
... and its done.
This line is probably unnecessary and likely to cause problems later:
self.articulationsArray = [NSMutableArray arrayWithArray:fetchResults];
Why would you need a mutable array of fetched objects? You can't really add or remove anything from the array directly while maintaining your graph integrity without refetching.
Just:
self.articulationsArray = fetchResults;
will work fine for most cases.
The more objects you create, the more chances for a leak you create. Keep things as simple as possible.
Well... I feel like a goose.
When I popped back to my first tableViewController, I wasn't releasing articulationsArray.
I was using
- (void)viewDidUnload {
[self.articulationsArray release];
}
When I should have been using:
-(void)viewDidDisappear:(BOOL)animated {
[self.articulationsArray release];
}
ViewDidUnload, was never being called.
Thanks for your help everyone.
精彩评论