iPhone: Crash When Deleting UITableView Rows - iphone

I am new in iPhone development. I am developing an application that fetches a value from a database and displays it in a table view. I want to delete table rows one by one but the rows do not delete and the application crashes.
Here is my row deletion code:
- (void)tableView:(UITableView *)tv commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(editingStyle == UITableViewCellEditingStyleDelete) {
SanjeevKapoorAppDelegate *appDelegate =(SanjeevKapoorAppDelegate *)[[UIApplication sharedApplication] delegate];
list *animal =[appDelegate.list1 objectAtIndex:indexPath.row];
[appDelegate deleteCoffee];
[self.tableView reloadData];
//Delete the object from the table.
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
I also delete all rows with this action:
-(IBAction)deletebtn:(id)sender{
SanjeevKapoorAppDelegate *appDelegate =(SanjeevKapoorAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate deleteCoffee];
[self.tableView reloadData];
}
How do I properly implement delete in an UITableView?

You need to change:
[self.tableView reloadData];
//Delete the object from the table.
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
to just:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
You are crashing because you're changing your data model to delete the row, then reloading the table such that the row no longer exist then telling the table to delete the non-existant row.
You don't have to call reload data in this instance because the table has already altered itself visually. You only call reload when a change in the data model forces a change in the table not when a table itself changes the data model.

Try wrapping the call to deleteRows in beginUpdates and endUpdates:
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[appDelegate deleteCoffee];
[self.tableView endUpdates];
I assume deleteCoffee affects how the table is populated. That must go between the update wrappers.
Or you can use reloadData without the other calls:
[appDelegate deleteCoffee];
[self.tableView reloadData];

Related

Showing a progress HUD while deleting UITableViewCell

I am attempting to delete a UITableViewCell while showing a progress HUD (in this case MBProgressHUD). This is necessary, as the Core Data entity being deleted is relatively large. When I run this code I get the following error message:
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 (2) must be equal to the number of rows contained in that section before the update (2), 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).'
The code being executed is:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self.tableView beginUpdates];
[SVProgressHUD showWithStatus:#"Deleting..." maskType:SVProgressHUDMaskTypeGradient];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
Garden *gardenToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSLog(#"Deleting garden '%#'", gardenToDelete.gardenName);
[self.managedObjectContext deleteObject:gardenToDelete];
[self.managedObjectContext save:nil];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Dismissing progress HUD");
NSLog(#"delete animation");
NSLog(#"deleting row");
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
NSLog(#"performFetch");
[self performFetch];
[SVProgressHUD dismiss];
});
});
[self.tableView endUpdates];
}
}
When it runs, I see the HUD appear, then the app proceeds to hang.
I am sure that this has to do with the structure of my multitasking.
managedObjectContext is not thread-safe. You need to create it for each thread.
When you call dispatch_async the first time, you're detaching that thread and allowing the method to continue to execute. This means that [self.tableView endUpdates]; is being called before [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
Instead, place your calls to [self.tableView beginUpdates]; and [self.tableView endUpdates]; inside your second call to dispatch_async when you reenter the main thread.

How to remove a cell from a UITableView at runtime?

I want to remove a specific cell from a UITableView
I found deleteRowsAtIndexPaths:withRowAnimation:
I tried to change the cell.frame to 0,0,0,0
I tried to .hidden = YES it
nothing works for me.
Any ideas?
Thank you!
Try adding the begin and end calls for editing:
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:deletePaths withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
Alternatively, if you are working with an underlying data source, remove the object from the datasource and call [tableView reloadData];
Use this method to remove the cell from your table view and hand to hand remove the same objects from your array by which you are showing data on tableview.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[yourArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
[tableView reloadData];
}
Hope this will help you..

Scroll to last UITableViewCell using scrollToRowAtIndexPath:atScrollPosition:animated using NSFetchedResultsControllerDelegate methods

I am adding a new item to the bottom of a UITableView and after inserting the item, I want the UITableView to scroll to the very bottom to display the newly inserted item. New items are saved to Core Data and the UITableView is automatically updated using NSFetchedResultsController.
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
switch (type) {
case NSFetchedResultsChangeInsert:
NSLog(#"*** controllerDidChangeObject - NSFetchedResultsChangeInsert");
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
//THIS IS THE CODE THAT DOESN'T WORK
[self.tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
break;
....
}
This leads to an out of bounds error, I can't seem to make it work. I can scroll to the second to last comment by adjusting the row of the index path, but I can't get to the very last item.
Basically, I'm adding a comment to a table of comments and after a comment is added, I want the table to scroll to the most recent comment.
You need to call endUpdates so that the tableView can calculate its new sections and rows. A simple case would look like this:
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:insertedIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
[self.tableView scrollToRowAtIndexPath:insertedIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
As you use NSFetchedResultsController, it is a bit more complicated, as the calls do beginUpdates, insertRowsAtIndexPaths:withRowAnimation:, and endUpdates are typically in different delegate methods. What you could do then is
add a property insertedIndexPath to store the inserted index path
after the -insertRowsAtIndexPaths:withRowAnimation: call in -controller:didChangeObject:atIndexPath:, add
self.insertedIndexPath = insertedIndexPath;
after [self.tableView endUpdates] in -controllerDidChangeContent:, add
if (self.insertedIndexPath) {
[self.tableView scrollToRowAtIndexPath:self.insertedIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
self.insertedIndexPath = nil;
}
See if this helps...
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
[self.tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

deleting a row out of table view

I am having trouble with my tableView crashing when I try and delete a row out of the table View. The method gets called correctly as the change is made in the database correctly. The error which I receive is:
Invalid update: invalid number of rows in section 0.
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [delegate managedObjectContext];
NSManagedObject *objectToDelete = [fixedArray objectAtIndex:indexPath.row];
[context deleteObject:objectToDelete];
[delegate saveContext];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
fixedArray = ([self mondayData]); // this is fetching the data for the array that I supply to the table view
[self.tableView numberOfRowsInSection:[fixedArray count]];
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [fixedArray count];
}
Your - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section method is likely not returning the appropriate number of rows. It should return the previous number of rows minus the number of rows that have just been deleted.
Also, if there are no more rows in the section, you must delete that section from the UITableView.
You need to include
[tableView beginUpdates];
and
[tableView endUpdates];
in your code. These two methods will prevent the UITableView from crashing while you delete or insert rows.
Put beginUpdates before you delete the tableView's row, and then endUpdates once you're all done.
Here's the documentation.
[tableView beginUpdates];
if (editingStyle == UITableViewCellEditingStyleDelete) {
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObject *object = [fixedArray objectAtIndex:indexPath.row];
[object setValue:#"No" forKey:#"selected"]; // this works and persists into the database
[delegate saveContext];
fixedArray = ([self mondayData]);
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:YES];
}
[tableView endUpdates];
[self.tableView reloadData];
This worked for me in the end.

How to delete row from table view?

I have a table view, data were retrieved from database and display in the table rows.
I have a remove button at the top navigation bar from removing table row.
When button is tapped, a red circle delete icon will appear.
After I select delete, it gave me and error call "Program received signal SIGABRT" at the [tableViewDelete rows......]
This is my code.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
Object = [array objectAtIndex:indexPath.row];
[ClassA ClassAMethod:[appDelegate getDBPath] :Object.ID];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
How do I remove a row from the table view?
Does anybody have any ideas or has anybody else achieved anything similar?
Thanks
I assume this line:
[ClassA ClassAMethod:[appDelegate getDBPath] :Object.ID];
deletes your object from database, while table is filled from some array instance - you need to delete an object from that array as well to maintain data integrity (array must be NSMutableArray instance):
Object = [array objectAtIndex:indexPath.row];
[ClassA ClassAMethod:[appDelegate getDBPath] :Object.ID];
// Add the following line
[array removeObjectAtIndex:indexPath:row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
try this code in editing delegate method of tableview:--
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[[self displayedObjects] removeObjectAtIndex:[indexPath row]];
// Animate deletion
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[[self tableView] deleteRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationFade];
}
i hope this can solve your problem