- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
PFObject *object = [_tdlArray objectAtIndex:(_tdlArray.count - indexPath.row -1)];
[object deleteInBackground];
//found the code for removing a row.
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
[tableView reloadData];
[object deleteInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!succeeded){
[tableView reloadData];
}
}];
}
}
I am able to successfully remove the data, but my app would crash every time I tap on the delete button. I think it has something to do with the [NSArray arrayWithObject:indexPath]
These are the error message
Assertion failure in -[UITableView _endCellAnimationsWithContext:]
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 (3) must be equal to the number of rows contained in that section before the update (3), 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).'
You want to delete the object then reload the data. Don't dispatch asynchronously the object to be deleted then tell the tableview you're deleting rows because the object has likely not been deleted yet, hence the error you're getting. Use the callback block to update the tableview after the object has been removed that way you can be sure that the object has been deleted. Also if you have a local store of the data that not bound to the data on the server, you need to remove the object from there as well.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//not sure how you're calculating the index here
PFObject *object = [_tdlArray objectAtIndex:(_tdlArray.count - indexPath.row -1)];
NSMutableArray *mutArray = [_tdlArray mutableCopy];
[mutArray removeObject:object];
_tdlArray = [NSArray arrayWithArray:mutArray];
[object deleteInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!succeeded){
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
[tableView reloadData];
}
}];
}
}
Related
Deleting a row from a UITableView fed by an NSFetchedResultsController causes my app to crash.
Error is:
* Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-2903.23/UITableView.m:1330
* 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 (1) must be equal to the number of rows contained in that section before the update (1), 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 want only swipe-to-delete. My deletion code goes like this:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView beginUpdates];
SequenceData *sd = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.managedObjectContext deleteObject:sd];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
}
My NSFetchedResultsController is set up just like in Ray Wanderlich's tutorial (http://www.raywenderlich.com/999/core-data-tutorial-for-ios-how-to-use-nsfetchedresultscontroller)
Number of rows is determined by:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id sectionObjects = [[self.fetchedResultsController sections] objectAtIndex:section];
NSInteger nbObjects = [sectionObjects numberOfObjects];
return nbObjects;
}
It looks like the fetch is not updating (number of rows does not vary). Do I need to fetch myself (isn't this taking care of by the fetch controller)?
There is obviously something basic I am missing here. Don't hesitate to suggest basic answers.
I first implemented this with the controller: didChangeObject: ... method. Error was the same, but some details differed.
Edit
I believe my problem is fixed. Both answers (From CX and Martin) helped me find it. Martin got the answer because of the explanations that helped me understand a little bit better...
Don't call
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
if you use a fetched results controller. Only delete the object with
[self.managedObjectContext deleteObject:sd];
The fetched results controller delegate method didChangeObject: is then called automatically,
and that calls deleteRowsAtIndexPaths:.
So in your case, the row was deleted twice, and that caused the exception.
Note that you don't need beginUpdates/endUpdates here.
If you want to delete a row you need to delete managedObject only.
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.managedObjectContext deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![self.managedObjectContext save:&error]) {
// handle error
}
}
Deleting the managed object triggers the NSFetchResultController delegate methods, and they will update the tableView.
Edit
You should implement NSFetchResultController delegate method
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath{
switch(type) {
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
////
default:
break;
}
Because when you work with data source like NSFetchedResultsController, all changes must come from there and your table only reflects them.
I added the following code in my iOS app to delete table cell from UITableViewController, but I get an error about the deletion.
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if(editingStyle == UITableViewCellEditingStyleDelete){
[self.toDoItems removeObjectAtIndex:indexPath.row];
NSArray *indexPaths = #[indexPath];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
Update:
toDoItems is just an NSArray, and I have tried the following code but is still not working:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if(editingStyle == UITableViewCellEditingStyleDelete){
NSArray *indexPaths = #[indexPath];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
[self.toDoItems removeObjectAtIndex:indexPath.row];
}
}
the error message is here:
'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (1003) must be equal to the number of rows contained in that section before the update (1004), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Xcode 6.2 iOS6
I have already tried Deleting table cell causes crash
The problem is that you are deleting the wrong object from your data model:
[self.toDoItems removeObjectAtIndex:indexPath.row];
That's too simple-minded. You have multiple sections in this table. You need a data model that distinguishes these sections, and you need to delete the correct row from the correct section in your data model before deleting the corresponding row from the table. You cannot do that by looking at indexPath.row alone; you need to structure your data model so as to take account of indexPath.section as well.
I have some problem with deleting rows from a tableView which is filled with coreData objects.
Trying to do this:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self.tableView beginUpdates];
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSLog(#"Deleting (%#)", [managedObject valueForKey:#"original_title"]);
[self.managedObjectContext deleteObject:managedObject];
[self.managedObjectContext save:nil];
[self performFetch];
[self.tableView endUpdates];
}
}
So, when I click the "Delete" button, the app crashes with the following Log:
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2872.3/UITableView.m:1254
2013-08-13 18:39:17.624 RR_proto[1076:a0b] *** Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections.
The number of sections contained in the table view after the update (1) must be equal
to the number of sections contained in the table view before the update (2), plus or minus
the number of sections inserted or deleted (0 inserted, 0 deleted).'
*** First throw call stack:
I also tried to add the following line after [self.managedObjectContext save:nil]:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
But the app crashes like before.
One more thing, everytime i start the app again after a crash through delete-action, the cell which should be deleted is really gone!
Would be very nice, if somebody can help.
I know there are many questions about similar problems and I tried different things from these, without success.
Thanks!
The table view is updated automatically by the fetched results controller delegate
methods when objects are added, deleted or modified.
Therefore, to remove an object, just delete it from the managed object context.
Don't call beginUpdates, endUpdates, deleteRowsAtIndexPaths or performFetch:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.managedObjectContext deleteObject:managedObject];
[self.managedObjectContext save:nil];
}
}
I have a editable tableView and i cant remove the last object heres my method :
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self deletePermittedFriend:[friendsIDs objectAtIndex:indexPath.row]];
[tableDataList removeObjectAtIndex:indexPath.row];
}
[tableView endUpdates];
}
and if the tableDataList MutableArray have only one last object gives me an error :
* Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-2380.17/UITableView.m:1070 2013-05-21
11:41:47.306 EzMall[3398:907] * 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 (0) must be equal to the number
of rows contained in that section before the update (1), plus or minus
the number of rows inserted or deleted from that section (0 inserted,
0 deleted) and plus or minus the number of rows moved into or out of
that section (0 moved in, 0 moved out).'
It looks that you forgot to call this UITableView method:
– deleteRowsAtIndexPaths:withRowAnimation:
BTW: It is always good practice to read error messages.
Try this
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableDataList removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
I am getting the error below from the following code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[self.tableView reloadData];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[[FavouritesController sharedController] removeFavouriteAtIndex:indexPath.row];
[self.tableView reloadData];
}
else if (editingStyle == UITableViewCellEditingStyleNone) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
Please can you tell me how to fix it?
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-1448.89/UITableView.m:995
2011-04-19 21:30:17.854 APPNAME[546:707] *** 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 (4) must be equal to the number of rows contained in that section before the update (4), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted).'
Change your model before you change your table.
So try:
[[FavouritesController sharedController] removeFavouriteAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
You probably don't need all those reloads unless the model changes more than just that one index path. The row deletion does some reloading on its own.
You probably want this code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[[FavouritesController sharedController] removeFavouriteAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleNone) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}