iOS - UITableView refresh table properly? - iphone

I have lots of data and lots of rows in my tableView.
when data changes I want to update my visible cells on the screen, I really don't want to use reloadData because it's an expensive call.
Is it possible to somehow update the visible cells only?
I tried calling : beginUpdate & endUpdate on the table, but that doesn't work all the time?
Any suggestions?

You can:
[tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows]
withRowAnimation:UITableViewRowAnimationNone];

For Swift 3:
tableView.reloadRows(at: tableView.indexPathsForVisibleRows!, with: .none)

Try calling 'deleteRowsAtIndexPaths', a method of UITableView, right after you delete the model from your data source. For example, if you are deleting a row in editing mode, you could write something like the code below. Note that the first line in the 'if' statement removes the object from the data source, and the second line cleans up the table:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ( editingStyle == UITableViewCellEditingStyleDelete ) {
[[[[[ItemsStore sharedStore] parameterArray] objectAtIndex:indexPath.section] objectForKey:#"data"] removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}

Related

At canEditRowAtIndexPath Method, reloadData of UITableView not work properly?

In my application, I reload my TableView ([tablView reloadData];) after delete row from TableView then canEditRowAtIndexPath Method alway call for (pervious) total number Of Rows.
For Example:
If i have 5 Rows on my TableView, then i delete 1 row from tableView. After deleting, I reload my TableView ([tablView reloadData]) but canEditRowAtIndexPath Method calls 5 time instead of 4 times ??
So i always got Following Error:
Terminating app due to uncaught exception 'NSRangeException', reason: '* **-[__NSArrayM objectAtIndex:]: index 5 beyond bounds [0 .. 4]'
I also tried to reload table after some delay (using NSTimer) but it also not worked for me.
I put some code here:
I apply canEditRowAtIndexPath on specific row which #"status" isEqualToString:#"directory" such like,
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%d", self.listOfSounds.count);
// Return NO if you do not want the specified item to be editable.
if([[[self.listOfSounds objectAtIndex:indexPath.row] objectForKey:#"status"] isEqualToString:#"directory"])
return YES;
else
return NO;
}
Code of delete row:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.sql_ deleteSoundFileAudioTableWhereMainID:[[self.listOfSounds objectAtIndex:indexPath.row] objectForKey:#"main_id"]]; /// delete record from DB
[self.listOfSounds removeObjectAtIndex:indexPath.row]; /// delete record from Array
[self updateListofSoundsFile]; /// Custom method
}
}
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO; // i also tried to return YES;
}
Here updateListofSoundsFile is my custom method code is :
-(void)updateListofSoundsFile
{
if(self.listOfSounds.count > 0)
[self.listOfSounds removeAllObjects];
self.listOfSounds = [self.sql_ getAllDataFromAudioTable]; // get all record from DB
NSLog(#"%d",self.listOfSounds.count);
[self.tblView reloadData];
}
Please Give any suggestion, How can i solve this issue ?
Thanks :)
you need to remove raw from tableview also befor remove item from array and reload data using this line becouse remove item from array but not tableview.
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.sql_ deleteSoundFileAudioTableWhereMainID:[[self.listOfSounds objectAtIndex:indexPath.row] objectForKey:#"main_id"]]; /// delete record from DB
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.listOfSounds removeObjectAtIndex:indexPath.row]; /// delete record from Array
[self updateListofSoundsFile]; /// Custom method
}
}
I ran into this same problem. The issue was that I deleted the object of the cell but when I used the reloadData method of the tableView, my canEditRowAtIndexPath method was not being called resulting in being able to edit cells that I do not want edited. The true fix was not calling the deleteRowsAtIndexPaths method, but the [tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; method.
Basically here is what was happening:
When I called reloadData:
The raw data was not being removed from the tableView as Nitin said. Therefore this is not the solution.
When I called deleteRowsAtIndexPaths:
iOS detected a discrepancy between the underlying data and the number of cells (because I had already removed the underlying object). The result was a crash which is also not the solution (obviously).
Now for The Fix!
When I called reloadRowsAtIndexPaths:
This caused the tableView to simply reload that single cell AND it got rid of the raw data. This is the solution.
Rather than removing the dataSource object, then trying to remove the cell that is essentially backed by nothing at this point (which causes a crash), simply remove the dataSource object, then reload that indexPath of the tableView
Here is the general format of the method:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[myDataSourceArray removeObjectAtIndex:indexPath.row];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
This is the first time I ran into the issue with the residual raw data that is not removed by simply calling the reloadData method. This is certainly the most elegant solution that I have seen thus far.
Happy Coding! I hope this helps.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.sql_ deleteSoundFileAudioTableWhereMainID:[[self.listOfSounds objectAtIndex:indexPath.row] objectForKey:#"main_id"]]; /// delete record from DB
[self.listOfSounds removeObjectAtIndex:indexPath.row]; /// delete record from Array
[self updateListofSoundsFile]; /// Custom method
}
[self.tblView reloadData];
}
When it comes to me, I analysed as below:
As commented by rmaddy on Nitin Gohel's answer:
You should always remove the data from the data source before updating the table.
I feels this is the ideal way.
If you are going to call reloadData, there is no reason at all to first call deleteRowsAtIndexPath.
This is also looks correct.
I analysed ambiguity, if I write reloadData its crashishing but once I write deleteRowsAtIndexPath it worked well.
Hope someone will emphasise on this issue for its causes etc.
the 'removeObjectAtIndex:indexPath' takes some time and I suspect your [self.tblView reloadData] is being called early. I tried a sample code and found success with [UiTableView beginUpdates] and [UiTableView endUpdates] you may also avoid crash if you put a little delay before the reloading or deleting rows haven't tried it though
[tableTable beginUpdates];
[tableArray removeObjectAtIndex:indexPath.row];
[tableTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableTable endUpdates];

how to delete the cell in table view

Can some one suggest what is the problem in my code.....
self.modleClass.foldersAray have one object and tableview have one section and one row
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[self.tableview setEditing:YES animated:YES];
[self.modleClass.foldersAray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YEs];
[tableView reloadData];
}
}
I am getting error as below.
*** 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 (1) must be equal to the number of rows contained in that section before the update (1), 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).'
Do like this,
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self.modleClass.foldersAray removeObjectAtIndex:indexPath.row];
[tableView reloadData];
}
}
it is more enough.........
If your tableView is based on the foldersAray, then removing an object from this array and reloading the tableview will result in the deletion of this cell.
You could remove the line:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YEs];
This error means, that you must update you datasource (array with data, dictionary or whatever you use)
For example:
You have 5 cells before delete and 5 object in dataArray. Before call to deleteRowsAtIndexPaths: we must remove object from dataArray, that associated with this cell and only then call deleteRowsAtIndexPaths:. Also instead use [tableView reloadData], use
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
P.S. I see, that you remove object from your datasource, so check it carefully, maybe you miss something
If you want animation try this, if you dont want animation use #Mountain Lion's answer.
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.modleClass.foldersAray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]withRowAnimation:UITableViewRowAnimationFade];
}
}
And if you have edit button on navigation, you should call
[self.tableView setEditing:YES animated:YES];
inside of your method to start editting.
IF the memory it takes does not matter for you... then you can dramatically delete (hide) cell by setting height to 0.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row%2) {
return 0;
}
return 100;
}
P.S: above dummy code will dramatically delete alternate cells.

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..

How to give action to 'Delete' in editButtonItem?

I've in my tableview i've
self.navigationItem.rightBarButtonItem = self.editButtonItem;
clicking on the minus button shows Delete button. I want to know how to give an action to this Delete button.
Tableview shows a list of items from sqlite database.I'm using Xcode 4.2
The delete button is already linked to your table view, and tapping it will send tableView:commitEditingStyle:forRowAtIndexPath: to your table view's data source. You do your deletion here.
This method is normally included in the template for UITableViewController subclasses.
If you look in to the UITableViewDataSource Protocol Reference you will find in there tableView:commitEditingStyle:forRowAtIndexPath:.
Asks the data source to commit the insertion or deletion of a
specified row in the receiver.
In this method you will get the index path for the cell to delete. You have to remove the corespondent element in four data source. And you also need to remove the table view cell.
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
When you press delete button it will automatically call this delegate method of UITableView:
- (void)tableView:(UITableView *)tableView commitEditingStyle:( UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath.
{
// Check if it's a delete button or edit button...
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Update the array and table view.
[eventsArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
// Commit the change.
NSError *error;
if (![managedObjectContext save:&error])
{
// Handle the error.
}
}
}
Implement tableView:commitEditingStyle:forRowAtIndexPath: in your table view data source (presumably your table view controller). See the docs on that method, or any of several Apple sample code projects (including what you get from the Xcode "master-detail app" template) for details & example usage.
I would add that you should make sure you are reloading the table data so it can update on the screen. Otherwise it will look like it didn't do anything.
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.myMutableArray removeObjectAtIndex:indexPath.row];
[self.tableView reloadData];
}

UITableview editing: done button does nothing

My table is populated with data from a sql DB. When I click on edit I can delete rows and the entry in the DB, but when I click on Done nothing happens.
To implement deleting I use commitEditingStyle:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//Get the object to delete from the array
buddies *buddyObj = [appDelegate.buddiesArray objectAtIndex:indexPath.row];
[appDelegate removeBuddy:buddyObj];
//Delete the object from the table.
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}
}
I have another table in this app and Edit/Done works fine.
The table with editing working is the first table showed when app starts, the non working table is called clicking on second item of a tabbar.
Any help is appreciated.
Thanks,
Max
Check that delegate is set properly.