Search code examples
iosobjective-ccore-datansmanagedobjectnsmanagedobjectcontext

Crash when trying to save NSManagedObject


Good day, everyone!

I have a UITableView. I need to add some object (with some properties, in this case I need at least name) to it and when I hit "+" at the navigation bar, new UIViewController presents modally and at viewDidLoad I call this method, that sets default name to it:

- (void)createManagedObject {

    NSManagedObjectContext *context = [[DVCoreDataManager sharedManager] managedObjectContext];
    NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"DVObject" inManagedObjectContext:context];

    [newManagedObject setValue:@"new object" forKey:@"name"];

    NSError *error = nil;
    if (![context save:&error]) {
        NSLog(@"%@", [error localizedDescription]);
    }

    self.currentObjectID = newManagedObject.objectID;
}

After I've entered name in UITextField I hit the "save" button and call that method, that I need to update name of the object:

- (IBAction)actionSaveTraining:(UIBarButtonItem *)sender {

    NSManagedObjectContext *context = [[DVCoreDataManager sharedManager] managedObjectContext];
    NSManagedObject *newManagedObject = [context existingObjectWithID:self.currentObjectID error:nil];

    [newManagedObject setValue:self.nameTextField.text forKey:@"name"];

    NSError *error = nil;
    if (![context save:&error]) {
        NSLog(@"%@", [error localizedDescription]);
    }

    [self dismissViewControllerAnimated:YES completion:nil];
}

And at this moment app crashes with an error:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (7) must be equal to the number of rows contained in that section before the update (7), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

I have NSFetchedResultsControllerDelegate methods implemented. controllerDidChangeContent: is called after createManagedObject method, but controllerWillChangeContext: is never called and I can't understand why.

- (void)controllerWillChangeContext:(NSFetchedResultsController *)controller {

    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeMove:
            break;

        case NSFetchedResultsChangeUpdate:
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeUpdate:    
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        default:
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {

    [self.tableView endUpdates];
}

How can I resolve this error? Maybe there is a better way to do what I need? (set default name at creation and when saving, set the name from uitextfield)


Solution

  • You have entered the name of the controllerWillChangeContent method incorrectly: the final word should be content not context:

    - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    
        [self.tableView beginUpdates];
    }