Jadzia
Jadzia

Reputation: 5

NSFetchedResultsController requires a non-nil fetch request and managedObjectContext error

Using core data on a on an application that has tabbed views. The second tab loads the core data, no errors show up in Xcode or when I run the app but when I click on the second tab the app crashes with the error "An Instance of NSFetchedResultsController requires a non-nil fetch request and managedObjectContext.

I'm new to core data and really struggling with this error so would appreciate any help I can get. The implementation file has the following code

- (void)setupFetchedResultsController
{
    // 1 - Decide what Entity you want
    NSString *entityName = @"EatCategory"; // Put your entity name here
    NSLog(@"Setting up a Fetched Results Controller for the Entity named %@", entityName);

    // 2 - Request that Entity
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];

    // 3 - Filter it if you want
    //request.predicate = [NSPredicate predicateWithFormat:@"EatCategory.name = Blah"];

    // 4 - Sort it if you want
    request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name"
                                                                                     ascending:YES
                                                                                      selector:@selector(localizedCaseInsensitiveCompare:)]];
    // 5 - Fetch it
    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                        managedObjectContext:self.managedObjectContext
                                                                          sectionNameKeyPath:nil
                                                                                   cacheName:nil];
    [self performFetch];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self setupFetchedResultsController];

    if ([[self.fetchedResultsController fetchedObjects] count] == 0) {
        NSLog(@"No Results were fetched so nothing will be given to the table view");
    }
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Eat Category Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

    }

    // configure the cell...
    EatCategory *eatcategory = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = eatcategory.name;

    return cell;
}


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    if (editingStyle == UITableViewCellEditingStyleDelete) {

        [self.tableView beginUpdates]; // Avoid  NSInternalInconsistencyException

        // Delete the role object that was swiped
        EatCategory *eatCategoryToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
        NSLog(@"Deleting (%@)", eatCategoryToDelete.name);
        [self.managedObjectContext deleteObject:eatCategoryToDelete];
        [self.managedObjectContext save:nil];

        // Delete the (now empty) row on the table
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [self performFetch];

        [self.tableView endUpdates];
    }
}

Upvotes: 0

Views: 3179

Answers (1)

Lorenzo B
Lorenzo B

Reputation: 33428

Are you sure you are setting the managed object context properly? It seems that the fetch request is ok but what about the context? If the context is not set properly this could lead to that error.

Do you inject the context from an external object? If yes, how is declared the managedObjectContext property?

For example:

// from an external object
YourController *controller = ... // alloc-init the controller
controller.managedObjectContext = self.managedObjectContext;

// within your controller .h
@property (strong, nonatomic) NSManagedObject* managedObjectContext; // or retain if you don't use ARC

// within your controller .m
@synthesize managedObjectContext;

You could also grab the main context inside your controller from the application delegate (if you have declared it there) like the following:

AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext* managedObjectContext = delegate.managedObjectContext;

but this could lead to a more rigid application design.

Some notes

Instead of using commitEditingStyle you could "register" for NSFetchedResultsControllerDelegate callbacks. This class has been created to deal with changes in table views. You could use it and respond in different manner for table changes.

Here the class reference for NSFetchedResultsControllerDelegate.

Hope it helps.

Upvotes: 1

Related Questions