amitsbajaj amitsbajaj - 15 days ago 5
iOS Question

Swipe to Delete a Cell in a Table using NSFetchedResultsController

I had previously a working implementation where I had a single TableViewController, I press the ADD button, it brings up another view controller which lets the user add text to fields - that in turn adds that information over to the entities and attributes and I could display that in the Table View. Implementing the following methods, I could swipe to delete a row successfully:

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}

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

if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.managedObjectContext deleteObject:[self.transactions objectAtIndex:indexPath.row]];
[self.transactions removeObjectAtIndex:indexPath.row];
[self.tableView reloadData];

NSError *error = nil;
if (![self.managedObjectContext save:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
[self.tableView reloadData];
}
}

}


Now, I've managed to successfully implement the NSFetchedResultsController to allow the same functionality with the adding and fetching of information, but just more secure. What I cannot figure out now is how to actually implement the same swipe to delete functionality.

I added the:

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}


I added this and the "swipe" gesture just doesn't work to delete cells.

In the NSFetchedReusltsController code for the datasource, I have:

- (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:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;

case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;

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

case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray
arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray
arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}


along with all of the required methods, but the swipe to delete action is just not working.

Any thoughts with this would be massively helpful.

Answer

To delete a row from the table, you just have to delete the corresponding Core Data object:

if (editingStyle == UITableViewCellEditingStyleDelete)
{
    [self.managedObjectContext deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];

    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        // handle error
    }
}

That's all, in particular you need not call reloadData. Deleting the object triggers the fetched results controller delegate methods, and that updates the table view.

Now from your code it seems that you have a data source array self.transactions. That is wrong and you should remove it. All data source methods must get the information from the fetched results controller directly.

Comments