Deleting all table rows in a section - objective-c

For my iPad project I need to be able to reload table rows.
This is how it should works, depend on some "id" selected from a popupview, i need to be able to reload table rows, table rows are dynamics and has a UITextField in it. I tried to use [self.tableView reload] but for some reason it does not update the rows correctly. Something like UITextField placeholder owned by previous "id" does not change. What I have in mind is to remove all cells in that specific section and reload the table with the new "id". When i do this i got this exception:
* 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 (3) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (0 inserted, 3 deleted).'
The project code:
- (void)selectedArchiefID:(NSString *) value {
[self.popOverController dismissPopoverAnimated:YES];
// collects all available document indexfields
int rowCount = [indexDefinities count];
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
for (int curIndex=0; curIndex < rowCount; curIndex++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:curIndex inSection:0]];
}
// deletes rows
if ([indexPaths count] > 0) {
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
//[self.tableView deleteSections:0 withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates]; //crashes here
}
[self.tableView reloadData];
}
Any idea what i did wrong?

Looks like you forgot to change the data of the datasource of the tableview.
You can't just change the tableview layout.
If you want to remove a section, you have to remove this section from the datasource first.
You could do this the easy way, by removing the section in a NSMutableArray (which is your datasource).
Or you could write a big if then else monster that figures out how much sections (and rows) to return in numberOfSectionsInTableView: and tableView:numberOfRowsInSection:.
Doesn't matter how you do it, but you have to remove the data before you update the tableview.
One more thing, having both [self.tableView beginUpdates]; /*...*/ [self.tableView endUpdates]; and [self.tableView reloadData]; in one method is usually useless. THe latter would kill the animation effect you get from the first one.

Related

Inserting new item in UITableView leads to invalid number of sections

I'm losing my mind here. Relevant code:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [[self.currentWorkout movements] count];
}
And...
- (void)addMovement:(Movement *)movement{
[self.currentWorkout.movements insertObject:movement atIndex:0];
[self.table beginUpdates];
NSIndexPath *path = [NSIndexPath indexPathForRow:0 inSection:0];
[self.table insertRowsAtIndexPaths:#[path] withRowAnimation:UITableViewRowAnimationTop];
[self.table endUpdates];
}
I have confirmed that insertObject:atIndex: is adding the object; the count of currentWorkout increases by one.
Error: 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (8) must be equal to the number of sections contained in the table view before the update (7), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).'
Solved: using wrong method to insert sections.
- (void)addMovement:(Movement *)movement{
[self.currentWorkout.movements insertObject:movement atIndex:0];
NSLog(#"%d",(int)[self numberOfSectionsInTableView:self.table]);
[self.table beginUpdates];
[self.table insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationTop];
[self.table endUpdates];
}
Removing the [self.table beginUpdates]; method call is important because otherwise the table will think it has the number of rows it would get after adding the object before that object is actually added.

crash application while delete section from UITableView

In tableview I have many sections, on the top row of section I have a delete button, I want to do delete section after clicking button but its crashing please help me how can I do this?? here is the code...
//****** adding delete section button
CellButton *_sectionButton = (CellButton*)[cell viewWithTag:10];
_sectionButton.hidden = YES;
_sectionButton.indexPath = indexPath;
[_sectionButton addTarget:self action:#selector(sectionDeleteButton:) forControlEvents:UIControlEventTouchUpInside];
-(void)sectionDeleteButton: (id)sender
{
CellButton *_secbtn = (CellButton*)sender;
NSInteger sectionNumber = _secbtn.indexPath.section;
[self.tableView beginUpdates];
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionNumber] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
[self.tableView reloadData];
}
EDIT: The error messsage is:
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1054 2013-07-04 04:25:15.921 estimation[9025:c07] *** 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 (2), plus or minus the number of sections inserted or deleted (0 inserted, 1 deleted)
I guess the numberOfSectionsInTableView: returns the previous number of sections. You must make sure that what you tell the table view to do also happens in the data source. That is, if you delete a section, then the numberOfSectionsInTableView must also return a number one less than before. The same stands for cells and everything else. This is probably described in the error you get.
You have to manage your number of sections in numberOfSectionsInTableview: delegate method
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//#warning Incomplete method implementation.
// Return the number of rows in the section.
return [MLControl shared].arrBuyList.count;//1;//[MLControl shared].arrBuyList.count;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
// [tableView beginUpdates];
NSLog(#"indexPath.row=%ld,indexPath.se=%ld",(long)indexPath.row,(long)indexPath.section);
[[MLControl shared].arrBuyList removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
// [tableView endUpdates];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
I met this problem, but the reason is different from yours.
When I add a section for the tableView, I reload data with this method, this also crash logging like yours:
[tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
Why do I use this method to reload my table? If I only refresh cells, this works fine, but I forgot I want to change the sections. For more information: What is More reliable way to reload UITableView Data?

Can't programmatically delete row from UITableView

I'm trying to implement a custom deletion process for my app, as my costumer doesn'y want the red circle provided by table view edition mode. I have added a deletion button for every row, with row number in its tag property. Once user clicks deletion button, it fires following method:
-(IBAction)deleteRow:(id)sender{
UIButton *tempButton = (UIButton*)sender;
[self updateTotals];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:tempButton.tag inSection:0];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView reloadData];
[sharedCompra removeItem:tempButton.tag];
tempButton=nil;
}
And I allways get this error:
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 (3) must be equal to the number of rows contained in that section before the update (3), 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).'
So I don't know if I'm missing something in this piece of code.
Many thanks.
You're trying to delete a row whereas your data source still reflects the original state (i. e. that before the deletion). You have to update the data source first, it's only then that you can issue a deletion from the table viev. You also don't need to set the button to nil, nor do you need to call - reloadData on the table view:
- (void)deleteRow:(id)sender
{
UIButton *tempButton = sender;
[self updateTotals];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:tempButton.tag inSection:0];
[sharedCompra removeItem:tempButton.tag];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
(One thing you should do, however, is paying attention to how you format your code.)
Call [sharedCompra removeItem:tempButton.tag]; before [tableView deleteRowsAtIndexPaths... and [tableView reloadData]
The problem is that when you call deleteRowsAtIndexPath: it is calling numberOfRowsInSection which returns the same count from your model.
Also reloadData call is not needed here.
When deleting and adding rows, you need to call beginUpdates, here how it should look.
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
and you don't need to call reloadData, or it will cancel the animation of the deleteRows, and insertRows methods. But you do need to reset the data, so if you're using an NSMutableArray, you need to remove the object first, so item at index 0, then you can delete row 0 in table. the number of rows needs to match the number of objects in that array when it ends deleting or it will also crash.

tableview won't update after adding objects to an array

I have a tableview inside a popover in my main view which is a web browser. Whenever the user visits a web page I want it to add the page to a list of recently visited websites. I have the code set up to add the URL as a string to the array that is the data source for the table view. The table view only shows the first site visited and won't show anything past that. However I know the sites are being added to the array because the array shows the Sites using NSLog statements after being added. However they still won't show up in the table. Can anyone help me?
EDIT:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [recentlyVisitedUrls count];
}
Also make sure you are returning the correct length of your array from – tableView:numberOfRowsInSection:
Try
[tableView reloadTable];
after you add the new data.
If you wan't animated updating, you can call:
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO]
If you need animation, it will be better read: Table View Programming Guide for iOS, you need Batch insert… part.
If you have a large table, [tableView reloadData] is probably not ideal. It'll also will reset your view to the beginning of the table, which may or may not be desirable. You might try something like this:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_model.recordCount - 1 inSection:0];
[_tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
[_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
BTW, _model is the data delegate class for the table in the example.
Also, make sure the data delegate updates it's total count correctly before you insert, or your app will crash on the insertRowsAtIndexPaths.

Objective c - Deleting rows of a table view

it's my first question in this awesome site. I've really searched a lot and yet find an answer to the next problem.
I have a table view with 9 cells. One of the cells has a switch button in it. When the switched button value changes, i want to delete 2 rows of the table view. I have written the next code:
- (IBAction)switchValueChanged:(id)sender {
NSLog(#"%#", ([switch isOn]) ? #"ON" : #"OFF");
NSArray *deleteIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:1 inSection:0],
[NSIndexPath indexPathForRow:2 inSection:0],
nil];
UITableView *tableView = (UITableView *)self.view;
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
// I Have to change the number of rows in the section here.
[tableView endUpdates];
}
When i run this, I'm getting a problem relating to the number of rows in the section - this number has been changed so i need to change it. I really can't find how i change it, but i know where i have to change it (see code).
How can i do it? how can i call the method numberOfRowsInSection:NSInteger and set also the rows?
Thank you very much :)
The number of rows in the table is in your
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
You need this to match the new number of rows in the table
---- EDIT
This means that you will need to keep track of the number of rows in your table.
Start with this set to 9 and delete 2 every time you change the switch
- (IBAction)switchValueChanged:(id)sender {
NSLog(#"%#", ([switch isOn]) ? #"ON" : #"OFF");
// We are going to delete 2 rows
numberOfRows -= 2;
...
and in your numberOfRowsInSection instead of returning 9 each time, return the new number of rows
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return numberOfRows;
}
You should delete the data from the datasource not the table cells and then just to refresh the table view. At least this is how i would do the design.
You have to also delete the data from the datasource of the table view. The data source is any container that holds the actual data which is being displayed on the table view. Just deleting the row only deletes the visual item of the row, when tableview is reloaded - it will want to draw 9-2 rows....but since number of rows is still returning 9, it will throw an inconsistency exception and tell you why. See the log carefully.