How to delete rows from UITableView with animation? - uitableview

I am having problems with deleting rows from table view. I am using the code below when the delete button in the row was pressed:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:control.tag-100 inSection:0];
[resultList removeObjectAtIndex:indexPath.row];
[resultView beginUpdates];
[resultView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[resultView endUpdates];
//[resultView reloadData];
First row was deleted successfully but then, indexes were not correct. So when I delete the last row, it gives index out of bounds exception.
The cell generation code is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"personalizeTableCell";
PersonalizeCell *cell = (PersonalizeCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[PersonalizeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.title.text = #"text";
cell.rateView.tag = indexPath.row + 100;
return cell;
}
Where am I wrong?
UPDATE:
for (NSInteger j = 0; j < [venuesTableView numberOfSections]; ++j)
{
for (NSInteger i = 0; i < [venuesTableView numberOfRowsInSection:j]; ++i)
{
PersonalizeCell* cell = (PersonalizeCell*)[venuesTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]];
cell.rateView.tag = 100 + i;
}
}
solved my problem. Thanks to Nenad M.

Assuming your [NSIndexPath indexPathForRow:control.tag-100 inSection:0]; returns the right index path....
Did you try moving the removeObjectAtIndex call inside the begin-/end-updates "bracket"?:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:control.tag-100 inSection:0];
[resultView beginUpdates];
[resultList removeObjectAtIndex:indexPath.row];
[resultView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[resultView endUpdates];
UPDATE:
Obviously your cell.rateView.tag become wrong, after youe delete your first cell.
So after every deletion (i.e. every removeObjectAtIndex...) you must re-iterate over your remaining tableview-cells an re-assign the proper tag-value (cell.rateView.tag = indexPath.row + 100)! Otherwise your [NSIndexPath indexPathForRow:control.tag-100 inSection:0]; will return a wrong indexPath, therefore leading to your out of bounds error!
Re-assigning the tag-values:
You don't have to reload the entire table, just loop through the remaining cells an re-assign the tag-value after [resultView endUpdates];:
NSMutableArray *cells = [[NSMutableArray alloc] init];
for (NSInteger j = 0; j < [tableView numberOfSections]; ++j)
{
for (NSInteger i = 0; i < [tableView numberOfRowsInSection:j]; ++i)
{
[cells addObject:[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]]];
}
}
Now do:
for (PersonalizeCell* cell in cells)
{
cell.rateView.tag = // new calculated tag
}
(Or do the re-assignment even in the inner-loop of the first code-snippet directly.)
Here's some really typical code for the whole process, two lines from the table in the example:
Note that facebookRowsExpanded is a class variable you must have:
if ( [theCommand isEqualToString:#"fbexpander"] )
{
NSLog(#"expander button......");
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSArray *deleteIndexPaths;
NSArray *insertIndexPaths;
facebookRowsExpanded = !facebookRowsExpanded;
// you must do that BEFORE, not AFTER the animation:
if ( !facebookRowsExpanded ) // ie, it was just true, is now false
{
deleteIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:2 inSection:0],
[NSIndexPath indexPathForRow:3 inSection:0],
nil];
[tableView beginUpdates];
[tableView
deleteRowsAtIndexPaths:deleteIndexPaths
withRowAnimation: UITableViewRowAnimationMiddle];
[tableView endUpdates];
}
else
{
insertIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:2 inSection:0],
[NSIndexPath indexPathForRow:3 inSection:0],
nil];
[tableView beginUpdates];
[tableView
insertRowsAtIndexPaths:insertIndexPaths
withRowAnimation: UITableViewRowAnimationMiddle];
[tableView endUpdates];
}
// DO NOT do this at the end: [_superTableView reloadData];
return;
}
NOTE: your code for numberOfRowsInSection must use facebookRowsExpanded
(it will be something like "if facebookRowsExpanded return 7, else return 5")
NOTE: your code for cellForRowAtIndexPath must use facebookRowsExpanded.
(it has to return the correct row, depending on whether or not you are expanded.)

Related

UITableview Insert/Delete

I am having one number of section base tableview in that plus button which will add new item in tableview.
While i try add or delete the section from tableview and reload that tableview it will blink old record many times and then add or delete the section. Here is the code.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SymbolTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectIndexPath containsObject:[NSNumber numberWithInt:(int)indexPath.section]])
{
[selectSymbol removeObject:cell.lblsymbol.text];
[selectIndexPath removeObject:[NSNumber numberWithInt:(int)indexPath.section]];
}
else
{
NSString *strr = cell.lblsymbol.text;
[selectSymbol addObject:strr];
[selectIndexPath addObject:[NSNumber numberWithInt:(int)indexPath.section]];
}
[tblDetail reloadData];
}
what is the issue?
try following code it may helps you
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
SymbolTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectIndexPath containsObject:[NSNumber numberWithInt:(int)indexPath.section]])
{
[tblDetail beginUpdates];
[selectSymbol removeObject:cell.lblsymbol.text];
[selectIndexPath removeObject:[NSNumber numberWithInt:(int)indexPath.section]];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
else
{
NSString *strr = cell.lblsymbol.text;
[tblDetail beginUpdates];
[selectSymbol addObject:strr];
[selectIndexPath addObject:[NSNumber numberWithInt:(int)indexPath.section]];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
}
You can reload cell which you removed/added
You will not reload all table.
Try the following code please
[self.tableView deleteRowsAtIndexPaths:#[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];
or
[self.tableView insertRowsAtIndexPaths:#[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];
for inserting row in tableview
- (void)insertNewObject:(id)sender
{
if (!arrayForTableContent) {
arrayForTableContent = [[NSMutableArray alloc] init];
}
NSInteger count = [arrayForTableContent count];
NSString *strTobeAdded = [NSString stringWithFormat:#"%d",count+1];
[arrayForTableContent insertObject:strTobeAdded atIndex:count];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:count inSection:0];
[self.tableViewForScreen insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
I'm not writing all the code nor test it in the debugger, but I will give you an advice of how to proper implement this. Let's say you have a datasource, like this:
NSMutableArray *data = #[#"First", #"Second", #"Third"];
Datasource: In numberOfRowsInSection, you return data.count; in cellForRowAtIndexPath, you will configure the cell with the respective index from the array;
Delegate: In didSelectRowAtIndexPath, remove the object from the data array, say you will need something like this: [data removeObjectAtIndex(indexPath.row)]; then call reloadData on the table view. The table view will smoothly return now just two items.

insertRowsAtIndexPaths or reloadData doesn't respond

Here is my code. And yesterday it works just fine. But this morning, it doesn't work.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
RSDrug *drug = [[RSDrug alloc]init];
[drugArray insertObject:drug atIndex:0];
NSIndexPath *ip = [NSIndexPath indexPathForRow:1 inSection:0];
[tableView insertRowsAtIndexPaths:#[ip] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return drugArray.count + 1;
}
I have tried to add some code like beginUpdates/endUpdates, or I delete insertRowsAtIndexPaths, just use reloadData.
But same result. When the app runs to insertRowsAtIndexPaths or reloadData, it stuck, no response.
So I need some help. How to solve this?
Found the problem..........A stupid mistake
There are two UITextFields in the added cell, and they all have the same leftView, my code is like this:
UIImageView *leftImage = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"img"]];
field_1.leftView = leftImage;
field_2.leftView = leftImage;
I never know that I can't reuse the leftView. If I set the leftImage to field1, I can't set it to field2 anymore.
When I changed to this, it works again.
field_1.leftView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"img"]];
field_2.leftView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"img"]];
Try this sequence...
NSMutableArray *indexPaths=[[NSMutableArray alloc]init];
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[tableView beginUpdates];
RSDrug *drug = [[RSDrug alloc]init];
[drugArray insertObject:drug atIndex:0];
if (indexPath.row == 0) {
[indexPaths removeAllObjects];
[indexPaths addObject:[NSIndexPath indexPathForRow:indexPath.row++ inSection:0]]; // here inserting row index=1;
[tableViewMenuList insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
}
[tableView endUpdates];
}
Have you tried this?
RSDrug *drug = [[RSDrug alloc]init];
[drugArray insertObject:drug atIndex:0];
[tableView beginUpdates];
// indexpath inserted is with the index 0 same with the `insertObject: `
NSIndexPath *ip = [NSIndexPath indexPathForRow:0 inSection:0];
[tableView insertRowsAtIndexPaths:#[ip] withRowAnimation:UITableViewRowAnimationAutomatic];
//here is what i use to do instead of #[]
//[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:ip] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
EDIT
Your code are working fine. i tested it. here..
Code:
Output:
Log:
Check the tested code above if you have omitted something.
I think the problem is the delegates of your table, make sure that your table have the delegate for both UITableViewDataSource & UITableViewDelegate.
Hope this is helpful.. Cheers.. :)

App stops when click back to previous screen

I'm filling a tableview with data from a server. I fill it well, but I have a function to display the details of each row in another screen, but when I push back, the app Crash, but I don't know why!!
This is my function:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 1) {
NSUInteger i, totalNumberOfItems = [gestiones count];
NSUInteger newNumberOfItemsToDisplay = MIN(totalNumberOfItems, numberOfItemsToDisplay + kNumberOfItemsToAdd);
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
for (i=numberOfItemsToDisplay; i<newNumberOfItemsToDisplay; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
numberOfItemsToDisplay = newNumberOfItemsToDisplay;
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
if (numberOfItemsToDisplay == totalNumberOfItems) {
[tableView deleteSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationTop];
}
[tableView endUpdates];
// Scroll the cell to the top of the table
NSIndexPath *scrollPointIndexPath;
if (newNumberOfItemsToDisplay < totalNumberOfItems) {
scrollPointIndexPath = indexPath;
} else {
scrollPointIndexPath = [NSIndexPath indexPathForRow:totalNumberOfItems-1 inSection:0];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 200000000), dispatch_get_main_queue(), ^(void){
[tableView scrollToRowAtIndexPath:scrollPointIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
});
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}else{
Gestion *ges = [gestiones objectAtIndex:indexPath.row];
DetalleGestionViewController *vcc = [[DetalleGestionViewController alloc] initWithNibName:#"DetalleGestionViewController" bundle:nil];
vcc.gestion = ges;
[self.navigationController pushViewController:vcc animated:YES];
NUEVA_GESTION = YES;
[gestiones removeAllObjects];
}
}
With "NUEVA_GESTION" I prepare the app to reload the table data.
Can someone help me?

UITableView insert row at top crashes

I'm trying to insert a row at the top of UITableView, but it crashes in the last line where I declare the endUpdating. This is the code I'm using and I'm using a button outside the table to insert row.
[comments insertObject:comment atIndex:0];
[self.commentsTableView beginUpdates];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.commentsTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.commentsTableView endUpdates]; //here crashes with "assertion failure"
I know I can just do insert in array and reload, but I want to do it with animation.
Thank you in advance.
This is my cell for row method
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CommentCell";
// Similar to UITableViewCell, but
ListingCommentTableViewCell *cell = (ListingCommentTableViewCell *)[theTableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[ListingCommentTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.commenterLabel.text = [[comments objectAtIndex:indexPath.row] objectForKey:#"user"];
[cell.commenterLabel sizeToFit];
cell.commentLabel.text = [[comments objectAtIndex:indexPath.row] objectForKey:#"text"];
[cell.commentLabel sizeToFit];
cell.lineView.frame = CGRectMake(5 , cell.commentLabel.frame.origin.y + cell.commentLabel.frame.size.height+ 5, cell.frame.size.width-20, 1);
cell.dateLabel.text = [Utils formatCommentDate:[[comments objectAtIndex:indexPath.row] objectForKey:#"createdOn"]];
return cell;
}
THis is my cell height method
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
int height = [Utils findHeightForText:[[comments objectAtIndex:indexPath.row] objectForKey:#"teksti"] havingWidth:screenWidth - 40 andFont:[UIFont fontWithName:#"Ubuntu" size:14]];
height += 25;
return height + 5;
}
and my number of rows method
- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section
{
return [comments count];
}
This is how I insert objects to UITableView with animation.
-(void)updateMethod {
[self.commentsTableView beginUpdates];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:0];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[comments insertObjects:[NSArray arrayWithObjects:comment, nil] atIndexes:indexSet];
[self.commentsTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.commentsTableView endUpdates];
}
You should check numberOfRowsInSection and be sure it reflect your comments.count
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return comments.count;
}
Also all UI updates must be done on the main thread, if you call your update method in different thread there is a change you can see that error.
You should update data source array inside animation block:
[self.commentsTableView beginUpdates];
[comments insertObject:comment atIndex:0];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.commentsTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.commentsTableView endUpdates];

Unable to remove all UITableView cells with animation

I can's seem to be able to remove all table rows. What seems to happen is that only the cells that are in view are removed and then the ones that were out of view move up. Also checked and my data source contains only the cels that are in view at the time of deletion. Heres the code
NSMutableArray *left = [[NSMutableArray alloc]init];
NSMutableArray *right = [[NSMutableArray alloc]init];
for(int i=0;i<dataSource.count;i++){
[dataSource removeObjectAtIndex:i];
NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0];
if(i%2==0)
[left addObject:ip];
else
[right addObject:ip];
}
[_view.tableView beginUpdates];
[_view.tableView deleteRowsAtIndexPaths:[NSArray arrayWithArray:left]
withRowAnimation:UITableViewRowAnimationLeft];
[_view.tableView deleteRowsAtIndexPaths:[NSArray arrayWithArray:right]
withRowAnimation:UITableViewRowAnimationRight];
[_view.tableView endUpdates];
What happens now is that only the cells in view are removed and the rest pop in after the removal (also the issue seems to pop up since the dataSource only contains the rows that are in view for some reason). What i want is to remove all the rows. Any ideas?
The problem is in the for loop condition. The dataSource.count gets smaller each iteration. Try this:
for(int i=0;i<dataSource.count;i++){
NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0];
if(i%2==0)
[left addObject:ip];
else
[right addObject:ip];
}
[dataSource removeAllObjects];
try something like this:
[_view.tableView beginUpdates];
UITableViewRowAnimation animation;
for(int i = dataSource.count - 1; i>= 0; i--)
{
[dataSource removeObjectAtIndex: i];
NSIndexPath* ip = [NSIndexPath indexPathForRow: i
inSection: 0];
if(i % 2 == 0)
{
animation = UITableViewRowAnimationLeft;
}
else
{
animation = UITableViewRowAnimationRight;
}
[_view.tableView deleteRowsAtIndexPaths: #[ip]]
withRowAnimation: animation];
}
[_view.tableView endUpdates];
You can do this in easy way...
[dataSource removeAllObjects];
[_view.tableView reloadData];
i think that you can put your dataSource = #[]; and [self.tableview reloadData]; and remove all cell in your tableview

Resources