I have a tableview that loading data from array called self.data .
Then i am trying to remove a row, so first i remove it from the data array, then i am trying to remove it from the table view with :
Data *d=[[Data alloc] init];
[d removeObject:ID];
NSLog(#"%ld",editingRow); //the right row to remove
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:editingRow inSection:0];
//update table
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
the crash is this :
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).'
Try below code in TableViewDelegate
[self.tableView beginUpdates];
[d removeObject:ID];
[self.tableView deleteRowsAtIndexPaths:[NSIndexPath indexPathForRow:ID inSection:0]
withRowAnimation:UITableViewRowAnimationRight];
[self.tableView endUpdates];
Related
I have a custom header for each section in tableView, and the headerView has a button. On click of that button, I'm trying to expand the section by changing the number of rows for that section. It works fine if I call reloadData, but it crashes when I try to use reloadSections/ insert/delete sections.
HEre is my number of rows method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (highlighHeaderClicked) {
return [_expandCountArray[section]integerValue]; // 9,9,9
}
return [_collapseCountArray[section]integerValue]; //2,2,2
}
So by default tableView shows 2 rows, when button is clicked, I want to show 9 rows.
and the button action method:
-(IBAction)highlightHeaderClicked:(id)sender{
highlighHeaderClicked = !highlighHeaderClicked;
NSIndexPath *indexPath = [self getIndexPathForView:sender];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:indexPath.length-1];
[self.tableView beginUpdates];
[self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView insertSections:indexSet withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
}
By doing this I got the excpetion:
Invalid update: invalid number of rows in section 2. The number of rows contained in an existing section after the update (9) 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, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
I also tried removing the object from datasource when the button action method gets called.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [_tempRowCountArray[section]integerValue]; //2,2,2
}
-(IBAction)highlightHeaderClicked:(id)sender{
highlighHeaderClicked = !highlighHeaderClicked;
NSIndexPath *indexPath = [self getIndexPathForView:sender];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:indexPath.length-1];
NSInteger rowCount = _mainDataSet.dashboardArray.count;
if (rowCount > 2) {
if (highlighHeaderClicked) {
[_tempRowCountArray replaceObjectAtIndex:indexPath.length withObject:#(rowCount)];
}else{
[_tempRowCountArray replaceObjectAtIndex:indexPath.length withObject:#2];
}
[self.tableView beginUpdates];
[self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView insertSections:indexSet withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
}
}
What am I missing here ? I think I am passing the right array count each time.
The basic problem you have is that you are trying to insert and remove whole sections. That means the number of sections would have to change.
Instead, you have to remove and insert rows in sections.
Also, you have to specify the exact difference between the previous state and the new state.
For example:
NSArray *rowsToBeAdded = ...
NSArray *rowsToBeRemoved = ...
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:rowsToBeAdded withRowAnimation: UITableViewRowAnimationBottom];
[self.tableView deleteRowsAtIndexPaths:rowsToBeRemoved withRowAnimation: UITableViewRowAnimationBottom];
[self.table endUpdates];
That also means you have to be very careful about your logic and keep track of the sections that are expanded.
You have to return the correct number of items for collapses and expanded sections:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
BOOL expanded = ...;
if (!expanded) {
return 0;
}
return ...
}
One other solution for this problem is to keep the rows always there and avoid inserts & deletes completely. You can return zero height for all hidden rows.
To update the height of all rows, you then simply call:
[self.tableView beginUpdates];
[self.tableView endUpdates];
I have a table view with two rows in one section, i.e
---
Row A
Row B
If I want to animate row 1 into a new section, i.e. the end result being:
---
Row B
---
Row A
how should this be achieved? What I have tried already is:
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow: 0 inSection: 0]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex: 1] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
However, in iOS 8 at least, the row animates out but then the new section is un-rendered (i.e. white, no bottom row border) until some time after when something triggers a redraw and it comes back.
[self.tableView beginUpdates];
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] toIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
[self.tableView endUpdates];
Which raises an exception:
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 (1), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).
And:
[self.tableView beginUpdates];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex: 1] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] toIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
[self.tableView endUpdates];
Which raises the exception:
cannot move a row into a newly inserted section (1)
Should I just not animate at all and reload the whole table?
You'll need to perform this in two steps.
First you'll need to add the section; you need to tell your data source to account for the new section. For a simple example like yours, you can just set a variable:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if(hasTwoSections)
return 2;
return 1;
}
Then where you want to trigger the animation, call:
hasTwoSections = true; // this needs to be set before endUpdates
[self.tableView beginUpdates];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex: 1] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
At this point, the tableView will call the data source methods to update the table based on your changes.
Once the section has been added, you can move the row to it in another update block:
[self.tableView beginUpdates];
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] toIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
[self.tableView endUpdates];
Obviously you'll need to update what numberOfRowsInSection returns to account for the change.
Although it's two steps, it will look like it's happening all at once.
I was in a similar situation where I was getting the exception cannot move a row into a newly inserted section (1). I only found two half solutions.
Reload the table with reloadData() - aggressive, and no animations
Delete and insert your rows, code below:
self.requestTableView.deleteRowsAtIndexPaths([oldIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
self.requestTableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
To get animations effects that give the impression of the rows moving, you could use UITableViewRowAnimation.Top when deleting, inserting, or reloading sections.
self.tableView.deleteSections(toDelete, withRowAnimation: UITableViewRowAnimation.Top)
self.tableView.insertSections(toInsert, withRowAnimation: UITableViewRowAnimation.Top)
self.tableView.reloadSections(toReload, withRowAnimation: UITableViewRowAnimation.Top)
Use -[UITableView moveRowAtIndexPath:toIndexPath:]
'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (6) must be equal to the number of rows contained in that section before the update (6), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
->#property (nonatomic ,strong) NSMutableArray *name;
- (id)initWithFrame:(CGRect)frame viewName:(NSInteger)viewDecide datasourceName:(NSMutableArray *)nameRef
{
}
when i intialize the above MutableArray in this class
like
self.name=[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3", nil];
then using table view editing delegate method , every thing works fine , when i click the button the table goes in edited mode with deletion and insertion.
but when i initialize the same array with data source which i passed in above method . the data inside the tableview render proprely but when i click the edit button its crash.
note:- i used
for row count-
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return[self.name count];
}
and for inserting
[strongSelf.tableViewDataView1 insertRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:0 inSection:0], nil] withRowAnimation:UITableViewRowAnimationLeft];
and for deleting i used
[strongSelf.tableViewDataView1 deleteRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:0 inSection:0], nil] withRowAnimation:UITableViewRowAnimationLeft];
:-strongSelf is used because this happening inside a block.
Your are removing the item from the table , not from your array. You have to remove the same from the array so that the count will remain same.
I'm having issues updating a collection view when receiving those updates via KVO.
e.g. for deletion I perform the following:
dispatch_async(dispatch_get_main_queue(), ^{
NSUInteger index = [self.albumObjects indexOfObject:oldObject];
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:index inSection:0];
[self.dataSource removeObjectAtIndex:index];
[self.collectionView deleteItemsAtIndexPaths:#[indexPath]];
}
The above gives me the error:
attempt to delete item 0 from section 0 which only contains 0 items before the update
Ok... so lets remove from the data source afterwards then which then returns the following error:
dispatch_async(dispatch_get_main_queue(), ^{
NSUInteger index = [self.albumObjects indexOfObject:oldObject];
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:index inSection:0];
[self.collectionView deleteItemsAtIndexPaths:#[indexPath]];
[self.dataSource removeObjectAtIndex:index];
}
However I now get the following error instead:
Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (1) must be equal to the number of items contained in that section before the update (1), plus or minus the number of items inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).
So it seems I can't win? What am I doing wrong here?
It seems the dispatch_async() causes the exception: when you modify your datasource (which adds your updater block to the end of the main queue), the item is already deleted when you try to update your collectionView.
What dataSource do you use? Is it managed manually? Or the the viewController is observing the datasource?
I'm getting an NSInternalInconsistencyException when trying to remove a single row from my table view. The table view contains several sections, with one row per section. I'm doing the following:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:index];
[indexPathToDelete addObject:indexPath];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPathToDelete withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
Before the update, I've updated my model (a NSArray containing one object for every row of my table view), deleting the object at index.
What am I doing wrong?
I've checked that I'm returning the correct number of sections after deleteing the object from the model and the table in the method -(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView.
Any hints?
Since you have one section per item, you also need to tell the table view that the section itself has been deleted with a call to deleteSections:withRowAnimation: inside your beginUpdates/endUpdates block.