Adrian
Adrian

Reputation: 16715

Delete NSManagedObject from managedObjectContext & tableView

I have a UITableView that displays attributes of entities that are in an array created with an NSFetchRequest. My instructor tells me for my purposes, I do NOT need a fetchedResultsController--so I do NOT need to add NSFetchedResultsControllerDelegate methods to my UITableViewController class. His analogy was putting a Porsche engine in a VW Beetle.

My tableView has 2 sections (0 and 1). Everything works fine until I try to delete objects from section 1 (section 0 is static).

With this commitEditingStyle code, the app crashes with his error:

*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], 
/SourceCache/UIKit_Sim/UIKit-3347.40/UITableView.m:1623

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

    if (editingStyle == UITableViewCellEditingStyleDelete && indexPath.section == 1) {
        // Delete cell
        [tableView beginUpdates];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [tableView endUpdates];


        // Delete LocationCategory from managedObjectContext
        LocationCategory *categoryToDelete = [self.locationCategories objectAtIndex:indexPath.row];
        [self.managedObjectContext deleteObject:categoryToDelete];
        [self.managedObjectContext save:nil];

    } else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }
}

When I restart the app, the locationCategory (my NSManagedObject) is no longer in the managedObjectContext. I know I've got a problem updating the tableView, but I don't know how to resolve it. I've dug around, tried a bunch of prospective solutions, but nothing resolves the crashing.

Here's how my array is created:

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

    self.title = @"Select a Category";

    // Core Data
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
    self.managedObjectContext = [appDelegate managedObjectContext];

    // Fetch LocationCategories & dump them in an array
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[NSEntityDescription entityForName:@"LocationCategory" inManagedObjectContext:self.managedObjectContext]];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"categoryName" ascending:YES];

    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:&sortDescriptor count:1];
    [fetchRequest setSortDescriptors:sortDescriptors];

    NSArray *categories = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
    self.locationCategories = categories;

    [self.tableView reloadData];
}

Update:

Here's what the code looked like at the end when it worked:

// This was previously an NSArray. It needs to be an NSMutableArray
@property (nonatomic, strong) NSMutableArray *locationCategories;

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete && indexPath.section == 1) {
        // Delete LocationCategory from managedObjectContext
        LocationCategory *categoryToDelete = [self.locationCategories objectAtIndex:indexPath.row];
        [self.managedObjectContext deleteObject:categoryToDelete];
        [self.locationCategories removeObjectAtIndex:indexPath.row];
        [self.managedObjectContext save:nil];


        // Delete cell
        [tableView beginUpdates];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [tableView endUpdates];

    } else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }
}

Upvotes: 0

Views: 286

Answers (1)

pbasdf
pbasdf

Reputation: 21536

Presumably your tableView datasource methods use self.locationCaregories. If so, the problem is that you don't remove the relevant Category from that array (although you delete it from the managedObjectContext, it remains in the array).

Now, because self.locationCategories is an NSArray, it is immutable, so you can't just remove the relevant item. You could reperform the fetch immediately after you delete the object, but that seems a bit inefficient. I recommend instead that you make self.locationCategories an NSMutableArray. You will need to amend the property definition, and also the line in viewWillAppear where you first set it:

    NSArray *categories = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
    self.locationCategories = [categories mutableCopy];

Then in the commitEditingStyle method, you can remove the relevant object from the array:

    LocationCategory *categoryToDelete = [self.locationCategories objectAtIndex:indexPath.row];
    [self.locationCategories removeObjectAtIndex:indexPath.row];

And as thorb65 says, move the code to delete the rows to the end of the method - you should get the data right, before you update the table.

Upvotes: 1

Related Questions