CoreData leaks when view is destroyed
I'm trying to finish an app but I'm having some memory leaks with CoreData when I delete the view from the navigation stack even though I released everything I created.
Basically the following method is called by the view below it.
+ (NSMutableArray *)getStoriesForSubscription:(Subscriptions *)s {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *storiesEntity = [NSEntityDescription entityForName:@"Articles" inManagedObjectContext:ikub.context];
[request setEntity:storiesEntity];
NSPredicate *predicate = [NSPredicate predicateWithForm开发者_运维问答at:@"(belongsTo == %@)", s];
[request setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"pubDate" ascending:NO selector:nil];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSMutableArray *stories = (NSMutableArray*)[ikub.context executeFetchRequest:request error:&error];
if (![ikub.context save:&error]) { NSLog(@"Cannot fetch the folders from the fetch request."); }
[sortDescriptors release];
[sortDescriptor release];
[request release];
return stories;
}
@implementation SubscriptionStories
@synthesize storiesTable, stories, subscription;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [stories count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
}
int index = [indexPath row];
cell.textLabel.text = [[stories objectAtIndex:index] title];
cell.detailTextLabel.text = [[stories objectAtIndex:index] desc];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if ([[[stories objectAtIndex:index] read] isEqualToNumber:[NSNumber numberWithBool:NO]]) {
cell.textLabel.textColor = [UIColor blackColor];
} else {
cell.textLabel.textColor = [UIColor grayColor];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
StoryDetails *details = [[StoryDetails alloc] init];
details.title = @"Detaje";
details.t = [[stories objectAtIndex:[indexPath row]] title];
details.d = [[stories objectAtIndex:[indexPath row]] desc];
details.l = [[stories objectAtIndex:[indexPath row]] link];
details.g = [[stories objectAtIndex:[indexPath row]] guid];
details.p = (NSString *)[[stories objectAtIndex:[indexPath row]] pubDate];
[SubscriptionsController setStoryAsRead:[[stories objectAtIndex:[indexPath row]] link] forSubscription:subscription];
[self.navigationController pushViewController:details animated:YES];
[details release];
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
stories = [[SubscriptionsController getStoriesForSubscription:subscription] retain];
[storiesTable reloadData];
}
- (void)viewWillDisappear:(BOOL)animated {
[stories release];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[subscription release];
[super dealloc];
}
Instruments says that the leak happens in this line:
stories = [[SubscriptionsController getStoriesForSubscription:subscription] retain];
If you have declared the property stories with retain then the extra retain is not necessary.
self.stories = [SubscriptionsController getStoriesForSubscription:subscription];
my suggestions:
remove (another?) leak by changing your UITableViewCell creation to return an autoreleased cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"] autorelease];
...
}
if that didn't help. (I had leaks were instruments was miles away from the actual leak). change your viewWillDisappear method to something like this
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[stories release];
stories = nil;
}
and add another release for stories in dealloc
- (void)dealloc {
[subscription release];
[stories release];
[super dealloc];
}
Maybe there are obscure ways that a dealloc happens without calling the viewWillDisappear: method.
I usually release everything in dealloc. As long as you make sure that you set an object to nil when you have released it in another method nothing bad will happen.
The leak was in a totally different place. Instruments isn't always right.
精彩评论