Removing a cell from the tableView - iphone

I have a tableview added to a viewController (I wanted it this way).
Each cell of the tableview has a segmentcontroller, when the user clicks on it the cell deletes/removes.
I end up getting an exception, and i have no clue how to solve it.
2012-01-23 15:35:26.729 TestProject [21003:707] * Assertion failure
in -[UITableView _endCellAnimationsWithContext:],
/SourceCache/UIKit/UIKit-1448.89/UITableView.m:995
2012-01-23 15:35:26.761 TestProject [21003: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 (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).'
My code so far;
in the button event;
UITableViewCell *cell=(UITableViewCell *)segmentController.superview.superview;
NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];
Person *person= [[self allThdata] objectAtIndex:indexPath.row];
[self.allThdata removeObjectIdenticalTo:person];
[self.myTableView beginUpdates];
[self.myTableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:YES];
[self.myTableView endUpdates];
I have also tried removeObjectAtIndex: indexPath.row and removeObject: person . None of this worked

Call to removeObjectAtIndex: should be inside beginUpdates block.
This should do the trick:
UITableViewCell *cell=(UITableViewCell *)segmentController.superview.superview;
NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];
[self.myTableView beginUpdates];
[[self allThdata] removeObjectAtIndex:indexPath.row];
[self.myTableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:YES];
[self.myTableView endUpdates];

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.

UITableView crashes when trying to delete a cell and section

I've been working on creating a UITableView that has its content loaded from a NSUserDefaults object. Whenever I attempt to delete a cell/section, however, the program crashes and spits out the following:
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1912.3/UITableView.m:1030
*** 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 (2) must be equal to the number of sections contained in the table view before the update (3), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).
No matter how much I read up on this error and try to fix it, I've been stuck here for the past few hours. Here is my method that is called when the user taps the "delete" button:
(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//[[[NSUserDefaults standardUserDefaults] objectForKey:#"rawArray"] removeObjectAtIndex:indexPath.row];
//[[[NSUserDefaults standardUserDefaults] objectForKey:#"rawDates"] removeObjectAtIndex:indexPath.row];
NSMutableArray *rawArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"rawArray"];
NSMutableArray *rawDates = [[NSUserDefaults standardUserDefaults] objectForKey:#"rawDates"];
[rawArray removeObjectAtIndex:indexPath.row];
[rawDates removeObjectAtIndex:indexPath.row];
[[NSUserDefaults standardUserDefaults] setObject:rawArray forKey:#"rawArray"];
[[NSUserDefaults standardUserDefaults] setObject:rawDates forKey:#"rawDates"];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationRight];
}
}
and here are the methods used to determine number of rows and cells:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [[[NSUserDefaults standardUserDefaults] arrayForKey:#"rawDates"] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return [[[NSUserDefaults standardUserDefaults] arrayForKey:#"rawDates"] objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 1;
}
The last method in there returns a one because, as of right now, I plan on only have one cell per each section. Thank you for taking the time to look over here, and I really hope you can help me out! :/
Check out the Batch Insertion, Deletion, and Reloading of Rows and Sections
Basically you need to put any calls of these method
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation: (UITableViewRowAnimation)animation;
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation: (UITableViewRowAnimation)animation;
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
between
- (void)beginUpdates;
- (void)endUpdates;
e.g.
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationRight];
[tableView endUpdates];
Your dataSource also needs to reflect the changes by the time endUpdates is called
Personally I like to make a category to give a block based wrapper around this to
stop me forgetting to call endUpdates
it allows indentation to look right / be automatic
Category on UITableView
#interface UITableView (PSAdditions)
- (void)ps_updates:(void (^)(void))updateBlock;
#end
#implementation UITableView (PSAdditions)
- (void)ps_updates:(void (^)(void))updateBlock;
{
[self beginUpdates];
if (updateBlock) { updateBlock(); }
[self endUpdates];
}
Which would look like this
[tableView ps_updates:^{
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationRight];
}];

exception while deleting a cell

I have given 2 colours to my cell.
cell.contentView.backgroundColor = indexPath.row % 2 ? [UIColor whiteColor] : [UIColor blackColor] ;
Now, when i delete a row, say i deleted the cell that contains the colour black, then there will be 2 rows that contains the colour white. So i tried refreshing the row;
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:YES];
This works, but when i delete all the records i get the following exception; Why is this ?
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1448.89/UITableView.m:961 and
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. Attempt to delete more rows than exist in section.'
my code;
[self.tableView beginUpdates];
[self.myArray removeObjectsInArray:discardedItems ];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:YES];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:YES];
[self.tableView endUpdates];
How can i solve this ?
It thinks you have more rows than you do. Try something like this...
[self.tableView beginUpdates];
[self.myArray removeObjectsInArray:discardedItems ];
[self.tableView reloadData];
[self.tableView endUpdates];
Due to the nature of the tableview's data delegate, once you modify your data model the rest should follow.
Ok, let's think that you have 6 objects in your array, each one corresponding to the data-source for each cell. So, the delegate methods are called and you can actually edit the row and remove it, so you will end up now with 5 objects. What I always do and works like a charm is first re-sizing the array with the data-source and then updating the view.
//Remove the data
[self.myArray removeObjectsInArray:discardedItems ];
//Update the view
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:YES];
[self.tableView endUpdates];
Unless you need to reload the data, meaning that some of the data-sources changed, you probably shouldn't be calling the update method. The exception was probably coming because you were trying to get info out of the sixth element of the array before you even finished updating the UITableView.
Hopefully this will work.

Adding a cell in UITableView with animation

I have a UITableView. I'm population it from a NSDictionary with arrays for each set of items on the table: labels, footers, Headers, UIViews, etc.
In section 0, I want a row #2 appear when a switch in row #1 is switched to on.
What I have done and it works is, in numberOfRowsInSection I added this code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (interruptor.isOn==NO && section==0) {
return [[[infoTableContentArray objectAtIndex: section] objectForKey:kLabelKey] count]-1;
}else{
return [[[infoTableContentArray objectAtIndex: section] objectForKey:kLabelKey] count];
}
}
and the action linked to the switch (interruptor) is:
-(IBAction)accioInterruptor:(id)sender{
[infoAndSettingsTable reloadData];
}
so when the switch is switched, the table reloads and the cell appears or disappears.
it actually works, but there is no animation, which makes it, mhh... well, you know.
I've tried to implement the reloadRowsAtIndexPaths:withRowAnimation, adding it to the code called by the switch:
-(IBAction)accioInterruptor:(id)sender{
[infoAndSettingsTable beginUpdates];
[infoAndSettingsTable reloadRowsAtIndexPaths:[[infoTableContentArray objectAtIndex: 0] objectForKey:kLabelKey] withRowAnimation:UITableViewRowAnimationBottom];
[infoAndSettingsTable endUpdates];
}
But, it dowsn't work. It crashed on the line [infoAndSettingsTable endsUpdates];
BTW, in all the cases the following:
[[infoTableContentArray objectAtIndex: 0]
is the array which contains the labels for that section.
Am I doing it right or I'm Epic-Failing alltogether?
Thanks in advance!
simple way to do this......
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
insertIndexPaths is an array of NSIndexPaths to be inserted to your table.
deleteIndexPaths is a array of NSIndexPaths to be deleted from your table.
Example array format for index paths :
NSArray *insertIndexPaths = [[NSArray alloc] initWithObjects:
[NSIndexPath indexPathForRow:0 inSection:0],
[NSIndexPath indexPathForRow:1 inSection:0],
[NSIndexPath indexPathForRow:2 inSection:0],
nil];
got it from this question
the argument to reloadRowsAtIndexPaths: should be an array of NSIndexPath objects identifying the rows you want to reload, not the labels for that section. Also, looks like you want to reload a section so I would try the following:
-(IBAction)accioInterruptor:(id)sender {
[self reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationBottom];
}
Why don't you just use UITableView's insertRowsAtIndexPaths:withRowAnimation:? It has been built exactly for this purpose, the UITableView class reference has the exact description and usage examples.
Apart from being cleaner it is also more performant since you don't have to reload the entire table (only really matters if you have lots of cells in it though)

Error : Number of Rows In Section in UITableView in iPhone SDK

I am getting this error while I am trying to load the data into my table view.
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 (73) must be equal to the number of rows contained in that section before the update (71), plus or minus the number of rows inserted or deleted from that section (3 inserted, 0 deleted).
What could be wrong?
Thanks
EDIT :
I am initializing the array on ViewWillAppear and adding new objects to the same array on Tableview's didSelectRowAtIndexPath method
Here is the code On viewWillAppear :
cellTextArray = [[NSMutableArray alloc] init];
[cellTextArray addObjectsFromArray:newPosts];
Here is the code which modifies the array on didSelectRowAtIndexPath :
[cellTextArray addObjectsFromArray:newPosts];
NSMutableArray *insertIndexPaths = [NSMutableArray array];
for (NSUInteger item = count; item < count + newCount; item++) {
[insertIndexPaths addObject:[NSIndexPath indexPathForRow:item
inSection:0]];
}
[self.table beginUpdates];
[self.table insertRowsAtIndexPaths:insertIndexPaths
withRowAnimation:UITableViewRowAnimationFade];
[self.table endUpdates];
[self.table scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionNone
animated:YES];
NSIndexPath *selected = [self.table indexPathForSelectedRow];
if (selected) {
[self.table deselectRowAtIndexPath:selected animated:YES];
}
Here newPosts is an array which has the values that are added to cellTextArray on
didSelectRowAtIndexPath method and viewWillAppear method.
If you have updated the array of data after initialization then you can call this method [yourTable reloadData].
And, it be better if you post the codes here. Then may be some one can help you quickly.
I think, the problem is with the statement in the didSelectRowAtIndexPath method.
You have added the following statement
[self.table insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationFade];
This statement adds the new rows to the table. but the number of rows in the datasource array for that section is different with the number of rows in that section of that table.
So the App is terminated.
Please try by removing the above statement and add required data to the dataSource Array at required indexes and reload the table
Regards,
Satya