views:

40

answers:

2

I have two UITableViewControllers with a fairly simple ui flow. One UITableViewController loads another UITableViewController when you select an item in the first UITableViewController.


(UITableViewController) List of Stories -> Select a Story -> (UITableViewController) List of Sentences


In the second UITableViewController (MakeSentenceDetailViewController) I can't release my NSFetchedResultsController without causing an error (shown with Zombies set to on):

-[NSFetchRequest release]: message sent to deallocated instance 0x5b370f0

The retain count of the NSFetchedResultsController stays at 1 but when I try to release it in dealloc I get a crash.

The code, especially in regards to the NSFetchedResultsController is the same in both tableviews, but in the MakeSentenceDetailViewController I can't release this NSFetchedResults Controller with a crash - giving me a leak.

How can I safely release my NSFetchedResultsController? Why does it work fine in the parent (first) tableviewcontroller - but not in the second?

I can provide code for the first UITableViewController but in regards to NSFetchedResultsController it's declared and used in much the same way.

MakeSentenceTableViewController.h:

@interface MakeSentenceTableViewController : UITableViewController {
NSManagedObjectContext  *managedObjectContext;  
NSFetchedResultsController *fetchedResultsController;
}
@property (nonatomic, retain)  Story *story;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@end

MakeSentenceTableViewController.m (relevant code with NSFetchedResultsController):

 - (void)viewDidLoad {
 [super viewDidLoad];
 if (managedObjectContext == nil) 
 { 
 managedObjectContext = [(MyAppAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
 NSLog(@"After managedObjectContext: %@",  managedObjectContext);
 }
   NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
  NSEntityDescription *entity = [NSEntityDescription entityForName:@"Sentence" inManagedObjectContext:managedObjectContext];
  [request setEntity:entity];
  //sorting stuff:
  NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"order" ascending: YES];
  NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortDescriptor, nil];
  [request setSortDescriptors:sortDescriptors];
  //[request setFetchBatchSize:FETCH_BATCH_SIZE];
  [sortDescriptors release];
  [sortDescriptor release];
  fetchedResultsController = [[NSFetchedResultsController alloc] 
    initWithFetchRequest:request managedObjectContext:managedObjectContext 
    sectionNameKeyPath:nil cacheName:nil];
  [request release];
  NSError *error;
  [fetchedResultsController performFetch:&error];
  NSLog(@"FetchedResultsController: %@", fetchedResultsController);
  NSLog(@"fetchedResultsController RetainCount at viewDidLoad: %d", [fetchedResultsController retainCount]);
 }

 - (void)dealloc {

  //Gotta figure out why I can't release this:
  [fetchedResultsController release]; //Crash! Burn! 
  NSLog(@"fetchedResultsController RetainCount at dealloc: %d", [fetchedResultsController retainCount]);
  [managedObjectContext release];
  [super dealloc];
 }
A: 
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
// ...snip...
[request release];

You're releasing an object that you've relinquished ownership of (with -autorelease). You don't get an error at the point of the other release because the NSFetchedResultsController is also retaining the fetch request; thus the controller is the one actually causing the crash when it releases the last reference to the fetch request.

John Calsbeek
Thankyou - that fixes the problem, but it also creates (or reveals) another. Now every third time (like clockwork) that I go into the MakeSentenceViewController (switching between TableViewControllers using the navigation controller) I crash on this line of code: managedObjectContext = [(MyAppAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; Can you see any obvious connection? It make be outside the scope of this question.
glenstorey
Depends on exactly how it's crashing.
John Calsbeek
Allright, I'd do some extra debugging over the next week or so - and post the solution here if I find it, if I can't I'll create a new Question. Thanks heaps for your time.
glenstorey
A: 

You are over-releasing the NSFetchRequest

You autorelease it here:

   NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];

then release it again later:

  [request release];

then later when you release the fetchedResultsController, it tries to release that same request again.

Firoze Lafeer