Deleting rows in uitableview - iphone

I am Having an application where, if the user enters data the rows will be updated with that data
Can i use One Single Button say 'delete' which when clicked will delete all the rows in the tableview at once.?

Yes you can do that. First remove all data from your data source, then reload your table. For ex. -
[yourArrayDataSource removeAllObjects];
[yourTable reloadData];
To animate the deletion of rows - do this in an IBAction method & link it to your UIButton. As soon as you press the button you will have a smooth awesome animation making all your rows fade out.
-(IBAction)deleteRows
{
[yourTable beginUpdates];
for(int i=0; i<[yourArrayDataSource count]; i++)
{
indexPath = [NSIndexPath indexPathForRow:i inSection:0];
[self.searchResTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
[yourTable endUpdates];
}
There are various animations that you can use here-
UITableViewRowAnimationBottom
UITableViewRowAnimationFade
UITableViewRowAnimationMiddle
UITableViewRowAnimationNone
UITableViewRowAnimationRight
UITableViewRowAnimationTop

make a button and in the button action method
-(IBAction)deleteRows
{
[array removeAllObjects];
[tableview reloadData];
}

Srikar's answer put me on the right track, but creates a lot of extra single item arrays, and calls deleteRowsAtIndexPaths far more than is needed.
-(void)clearTable
{
NSMutableArray *indexPaths = [NSMutableArray array];
for(int i=0; i<[self.myArray count]; i++)
{
NSIndexPath *anIndexPath = [NSIndexPath indexPathForRow:i inSection:0];
[indexPaths addObject:anIndexPath];
}
[self.myTableView beginUpdates];
[self.myTableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
self.myArray = [NSArray array];
[self.myTableView endUpdates];
}

Related

App crashes when refreshing table (Probably the call endUpdates on tableView causes the crash)

Came across this post but did not fix my problem.
iPhone app crashing on [self.tableView endUpdates]
Having a UITableView which loads articles from a newspaper website. First load works
as expected but when I use an UIRefreshControl to fetch the articles again my app crashes
when (animating) inserting rows.
Error:
Code:
- (void)insertRowsWithAnimation
{
NSMutableArray *indexPaths = [NSMutableArray array];
NSInteger i = self.latestArticlesArray.count - self.latestArticlesArray.count;
for (NSDictionary *dict in self.latestArticlesArray) {
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
i++;
}
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationMiddle];
[self.tableView endUpdates];
}
- (void)fetchEntries
{
UIView *currentTitleView = [[self navigationItem] titleView];
UIActivityIndicatorView *aiView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[[self navigationItem] setTitleView:aiView];
[aiView startAnimating];
void (^completionBlock) (NSArray *array, NSError *err) = ^(NSArray *array, NSError *err) {
if (!err) {
[[self navigationItem] setTitleView:currentTitleView];
self.latestArticlesArray = [NSArray array];
self.latestArticlesArray = array;
[self insertRowsWithAnimation];
}
};
[[Store sharedStore] fetchArticlesWithCompletion:completionBlock];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.latestArticlesArray.count;
}
If you want to see more methods please let me know. Hope you can help. From what I've learned so far I think the number of posts have changed therefore the table expects another amount of articles to show?
The line
NSInteger i = self.latestArticlesArray.count - self.latestArticlesArray.count;
sets i to zero, therefore insertRowsAtIndexPaths is called with an empty array.
I assume that your intention was to call insertRowsAtIndexPaths with the row numbers of the newly added rows, but then you have to remember the old data before replacing the array in
self.latestArticlesArray = array;
But note that since you replace the entire array, you can as well call
[self.tableView reloadData];
instead of beginUpdates/insertRowsAtIndexPaths/endUpdates.
Update: My first analysis is wrong (and wattson12's is correct). As you said in the comments, you need just a simple animation that removes all previous rows and inserts the new rows after a fetch. This can be done like this:
- (void)replaceArticlesWithAnimation:(NSArray *)articles
{
NSUInteger oldCount = [self.latestArticlesArray count];
self.latestArticlesArray = articles;
NSUInteger newCount = [self.latestArticlesArray count];
[self.tableView beginUpdates];
for (NSUInteger i = 0; i < oldCount; i++) {
[self.tableView deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
}
for (NSUInteger i = 0; i < newCount; i++) {
[self.tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[self.tableView endUpdates];
}
and in fetchEntries you call
if (!err) {
[[self navigationItem] setTitleView:currentTitleView];
[self replaceArticlesWithAnimation:array];
}
The reason it loads the first time is because you are inserting a number of rows each time, so on the first run the number of rows changes from 0 to the count in array (in the completion block), and you call insertRows with a number of index paths equal to the count of the array.
The 2nd time you call it you are inserting new rows, but you are not updating the count to reflect the new sum. You should be adding your existing array to the one returned in the completion block, and returning the count of that combined array in numberOfRowsInSection
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
});

Animation when UITableviewcell are being drawn

I have a fully working UITableView, with delete, sort, insert and etc.
How can I set animation like Fading, Middle or Down to the UITableViewCell when the cells are being added to the UITableView, not when using UITableViewCellEditingStyleInsert, but when items are being added from an array
have you tried to insert a cell (with insertRowsAtIndexPaths:withRowAnimation:) for each object you add?
Probably something like this:
- (void)addContentFromArray:(NSArray *)array {
[self.tableView beginUpdates];
NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array) {
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:[self.dataSource count] inSection:0];
[self.dataSource addObject:object];
}
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}

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)

how to clear all the rows of uitableview

I added a button on the uinavigationbar I want to use it to clear all the rows of uitablview
How can I do that?
A bit late... but try this:
Where you want to clear the table:
// clear table
clearTable = YES;
[table reloadData];
clearTable = NO;
This function should look like:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(clearTable)
return 0;
(...)
}
There should be a UITableView delegate method that populates the UITableView control:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Find this method and change where the data for each cell is being pulled from. If you are currently using the indexPath to access an array of values to populate your tableView cells, you can programmatically switch to an array of empty values, or even just return empty cells from this method when the condition is right.
Simple.. set your data source (NSArray or NSDictionary) to nil and [self.tableView reloadData]!
What do you exactly mean by clearing the row? Do you still want them to be there, but without text? If yes, here's this code:
UITableViewCell *cell;
NSIndexPath *index;
for (int i = 0 ; i < count; i++) {
index = [NSIndexPath indexPathForRow:i inSection:0];
cell = [tableView cellForRowAtIndexPath:index];
cell.textLabel.text = #"";
}
If you want to delete them, you can use this code:
[uiTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:index] withRowAnimation:UITableViewRowAnimationFade];
Before you are reloading the table remove all objects from your tableView array (The array which populated your tableView) like so:
[myArray removeAllObjects];
[tableView reloadData];
The crash is occurring because you need to reset number if rows count in the -
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [tempArray count];
}
one way is use a flag variable as below:
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
if (deleting)
return rowcount;
else
return [tempArray count];
}
Also you need to modify the deleting code as below:
deleting = YES;
for (i = [uiTable numberOfRowsInSection:0] - 1; i >=0 ; i--)
{
NSIndexPath *index = [NSIndexPath indexPathForRow:i inSection:0];
[uiTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:index] withRowAnimation:UITableViewRowAnimationFade];
rowcount = i;
}
deleting = NO;
[uiTable reloadData];
in your .h file
BOOL deleting;
NSInteger rowcount;
Hope this helps...
The rowcount = i should go before the call.
[uiTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:index]
withRowAnimation:UITableViewRowAnimationFade];
Otherwise, it will crash.
tableView.dataSource = nil
tableView.reloadData()

RowAnimation looks weird with different height cells

I have a problem with animating deletes and inserts on a UITableView. The Fact ist, that I have different cell heights, some 44.0 some 135.0 now. I have uitableviewstylegrouped with different sections. The first row of each sections is a grouping row. On click I remove all rows of this section except the grouping row. But that animation looks weird, when animating (UITableViewRowAnimationTop) the 135px height cell. I tried to set self.tableview.cellheight to 135 and commented out the tableView:cellHeightForIndexPath-Method. And the Animation works fine. Or I set every cellheight to 135 in tableView:cellHeightForIndexPath-Method.
It looks like the animation process checks the height of the first row in the sections an takes that height of the cell for all following cells to animate.
Somebody has an idea?
- (void) showhideGroup:(int)group
{
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
MCGroup *handleGroup = [groups objectAtIndex:group];
NSMutableArray *groupRows = [visibleGroupData objectForKey:handleGroup.title];
[self.tableView beginUpdates];
if (!handleGroup.hidden) {
int row = 0;
for(MobileFieldMapping *field in groupRows)
{
if (![field.datatype matchesInsensitive:GROUPING_CELL])
{
NSIndexPath *path = [NSIndexPath indexPathForRow:row inSection:group];
[indexPaths addObject:path];
}
row++;
}
row = 0;
for(NSIndexPath *index in indexPaths)
{
[groupRows removeObjectAtIndex:index.row-row];
row++;
}
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
handleGroup.hidden=YES;
}
else
{
NSMutableArray *allGroupRows = [groupData objectForKey:handleGroup.title];
int row = 0;
for (MobileFieldMapping *field in allGroupRows)
{
if (![groupRows containsObject:field])
{
NSIndexPath *path = [NSIndexPath indexPathForRow:row inSection:group];
[indexPaths addObject:path];
[groupRows insertObject:field atIndex:row];
}
row++;
}
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
handleGroup.hidden=NO;
}
[self.tableView endUpdates];
[indexPaths release];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if ([cell isKindOfClass:[FormCell class]])
{
return [(FormCell*)cell height];
}
return 44.0;
}
I had the same problem.
My workaround is to use fade section animation:
[tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
Instead of one for elements:
[tableView deleteRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationTop];
This looks much smoother.
An old one that is still unanswered. I assume you figured it out a long time ago, but here is my first thought. (I recall trying to do something like this myself.)
When the UITableView calls heightForRowAtIndexPath:, it will be because the table is trying to prepare the cell, so you can't use the cell to return the height. This may cause an infinite regression in calls or it may detect this and just give up or throw an exception and leave you holding the bag.
You must calculate the cell height without using the cell itself.
As for the cell height assumption, try calling insert/delete for individual cells rather than a single call to do it all at once. The UITableView will still batch them up for the animation after you call endUpdates.