how to clear all the rows of uitableview - iphone

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()

Related

Adding dynamic sub-rows by selecting tableview row in tableview iPhone errors?

I want to add row dynamically. I have tableview list of building names. If some one choose building(didSelectRowAtIndexPath) then respective floors of building should get added dynamically as subrow. Its like maximizing and minimizing the subrow on respective building list selection. How do I do this. Thanks in advance...
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// There is only one section.
if (tableView == indoortable || tableView == indoortable_iPad)
{
return 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of time zone names.
if (tableView == indoortable || tableView == indoortable_iPad)
{
return [indoorZones count];
}
}
cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == indoortable || tableView == indoortable_iPad)
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleGray; //cell bg
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Set up the cell.
//cell.textLabel.text = [copyListOfItems objectAtIndex:indexPath.row];
cell.textLabel.text =[indoorZones objectAtIndex: indexPath.row];
//[cell setIndentationLevel:[[self.indoorZones objectAtIndex:indexPath.row] intValue]];
return cell;
}
}
didSlectRowAtIndexPath method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
zonesFloor = [[NSMutableArray alloc]init];
zonesFloorA = [[NSArray alloc] initWithObjects:#"Gr fl",#"1st fl",#"2nd fl",nil];
[zonesFloor addObject:zonesFloorA];
if (tableView == indoortable )
{
NSUInteger i=indexPath.row+1;
for (NSArray *count in self.indoorZones) //app is crashing here giving error.......Collection <__NSArrayM: 0x4b1d550> was mutated while being enumerated.
{
[zonesFloor addObject:[NSIndexPath indexPathForRow:i inSection:0]];
[self.indoorZones insertObject:zonesFloor atIndex:i++];
}
[[self indoortable] beginUpdates];
[[self indoortable] insertRowsAtIndexPaths:(NSArray *)zonesFloor withRowAnimation:UITableViewRowAnimationNone];
[[self indoortable] endUpdates];
}
if (tableView == indoortable_iPad )
{
//some logic
}
[tableView deselectRowAtIndexPath:selectedIndexPath animated:NO];
}
It Gives following error [__NSArrayI compare:]: Or [NSIndexPath _fastCStringContents:]: unrecognized selector sent to instance. I tried many ways but may be I am lacking somewhere. Please suggest. thanks in advance.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSIndexPath *selectedIndexPath = [self.indoortable indexPathForSelectedRow];
zonesFloorA = [[NSArray alloc] initWithObjects:#"Gr fl",#"1st fl",#"2nd fl",nil];
if (tableView == indoortable )
{
for (NSString *str in zonesFloorA) {
[indoorZones addObject:str];
}
//[[self indoortable] beginUpdates];
//[[self indoortable] insertRowsAtIndexPaths:(NSArray *)zonesFloor withRowAnimation:UITableViewRowAnimationNone];
//[[self indoortable] endUpdates];
}
if (tableView == indoortable_iPad )
{
//some logic
}
[tableView reloadData];
}
may this meet your requirement
Okay, so not to sound mean, but there are almost too many issues here to count.
Let's start with a basic explanation of how tableView's work so that you can start to fix this:
First, the tableView asks how many sections are in the table by calling:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
}
In your code, you simply tell it that it has one section. However, in your later code, when you try to add rows to your table, you tell it that you want to add your rows to a second section (with an index of 1). Therefore, you either need to add these rows to section 0 instead, or update the above method to tell it that, sometimes, there are two sections.
Second, the tableView asks how many rows are in each section of the table by calling:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
}
In your code, you are simply returning the number of zones. However, like above, you need to include the rows that you have added to your table. If you are adding them to a different section, then you need to return different values, depending on how many rows are in the section with the index asked for in the section variable. If they are all in the same section, then you need to add them up and return the correct value.
Third, the tableView asks for an actual cell for the row by calling:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
}
In your code, you are only returning a cell which has data populated by the indoorZones array, but you also need to supply cells which are configured properly for the specific zone/floor. Again, you either need to determine this by section number or row number as appropriate.
Finally, when you click on a row, the tableview tells you by calling the following method:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
In this method, you need to update your data source that is used by the previous functions so that when they get called again, they will provide the correct data. Your data source must mirror the way that you want your table view to look. In your case, you have an array called indoorZones. This is good if you just want to display a list of zones, which is what you start off doing. However, when you want to add more rows, you need to add more rows to your data source first, so that when the tableView starts this process over, it is already there.
If you want everything to stay in one section, then I would come up with a data source that can include both types of rows, and be able to distinguish between them so that cellForRowAtIndexPath can create the proper type of cell and return it.
If you want two sections, then I would add a second array for the second section (since it is not the same type of data) and return the appropriate values in each of these methods, based on which array you need to use for that section.
I hope this helps!

Strange animation when moving last row out of section and deleting section

I have a multi-section tableview. In edit mode I allow rows to be moved from one section to another. Once the final row is removed from one section I delete that section. So I am using deleteSection inside moveRowAtIndexPath.
When the final item is moved from the section, the section header disappears as planned. But there is a very strange animation bug, where the moved row seems to 'merge' with the row it is dropped above, and an empty row is displayed at the bottom of the 'to' section (probably because the numberOfRows for that section is correct, but 2 rows are in the same position). Even stranger, when I click the reorder control for this row (not moving the item, simply touching and releasing), the two items 'unmerge'.
I have posted a video demonstrating this.
I have tried wrapping my data changes and view changes in begin/end updates, but to no avail.
I have uploaded a test project here, and I will also post the code below. A couple of points:
I have tried to replicate my data source's format in the demo project, in case this is where the problem originates. The key thing is that my source is a composite array of two other arrays (though I can't see why this would be an issue).
To see the behavior in question, move the two rows in the bottom section, up into the top section. Don't drop them in the last row on the top section though, since this seems to work ok.
Moving rows the other way, from the top section to the bottom section, is buggy in this demo project.
Code (all of this is in the demo project):
I set up my arrays in loadView:
- (void)loadView{
array1 = [NSMutableArray array];
[array1 addObject:#"test 0"];
[array1 addObject:#"test 1"];
[array1 addObject:#"test 2"];
array2 = [NSMutableArray array];
[array2 addObject:#"test a"];
[array2 addObject:#"test b"];
[super loadView];
}
I also have a method that returns a combination of these arrays - this is used as the data source:
- (NSMutableArray *)sourceArray{
NSMutableArray *result = [NSMutableArray array];
if (array1.count > 0) {
[result addObject:array1];
}
if (array2.count >0) {
[result addObject:array2];
}
return result;
}
Which allows for very simple number of rows/sections:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return self.sourceArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[self.sourceArray objectAtIndex:section] count];
}
Standard Cell/Header formatting:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.textLabel.text = [[self.sourceArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [NSString stringWithFormat:#"Section %i", section];
}
This is where I do the magic
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
I notice that the row that comes from the to-be-deleted section is the one that disappears until you retouch the order control.
I suspect that when this datasource method is called by the tableview, its state is still in the middle of performing the move, so calling 'deleteSections' will make the table try and delete the row you're moving. It's not so much of a merge as the fact that it's fading away at the same rate as the section header, and the one below it is just scooting back up to fill the space.
Tapping the control causes the table view to rejigger itself and realize that the row isn't actually gone.
to try and work around this, try running the deletion in the next runloop, via a dispatch call, like:
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
dispatch_async(dispatch_get_main_queue(), ^() {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
});
}
this will cause the deletion to run on the main thread still, but allow the 'moveRow' and whatever call stack it happens to be in finish up its logic before the deletion call
Your problem is in the animation. One is being done while another is not yet finished (moving & deleting animation) causing one cell to be drawn upon the other. You can verify this by moving the cells around again. The correct order will then be displayed. According to Apple's docs on the UITableView:
Note: The data source should not call setEditing:animated: from within its implementation of tableView:commitEditingStyle:forRowAtIndexPath:. If for some reason it must, it should invoke it after a delay by using the performSelector:withObject:afterDelay: method.
Therefore to fix this, do this to your code:
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self performSelector:#selector(someMethod:) withObject:fromIndexPath afterDelay:1.0];
}
- (void) someMethod:(NSIndexPath *) fromIndexPath {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
Should work fine. Just change the delay to something shorter that suites you.
On the off chance that your rows or what's inside them can take focus, have you checked that you have called resignFirstResponder or [view endEditing:YES]? We saw this when we used text fields and (IIRC it was iOS 4 version dependent too) left the focus in one of the fields.
You have to reload the tableview after deleting the section. Try this code.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}
}
Swap the order of fromArray and toArray in your code. If the item has a retain count of 1 prior to removing it from the array, it will have a retain count of 0 before adding it to toArray.
If you swap the order, the item will go from retain count of 1 to 2 then back to 1 when the remove is complete.
I think the UITableViewRowAnimationFade animation is interfering with the UITableViewCell move animation. One thing you can try is to delay the section deletion a little bit late in order for the cell move row animation to finish.
Try replace your code with the following code.
-(void)deleteSection:(NSIndexSet*)indexSet
{
[self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
}
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self performSelector:#selector(deleteSection:) withObject:[NSIndexSet indexSetWithIndex:fromIndexPath.section] afterDelay:1.0];
// [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
a solution that lost animation on last row :
if([listOfItemsOnTransaction count]==indexPath.row){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}else
{
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationFade];
}

UITableView SelectAll - willDeselectRowAtIndexPath alternative

I built a multi-selection table, I did that using willSelectRowAtIndexPath and willDeselectRowAtIndexPath. It is working fine. Now I want to programatically selectALL or Select None. Is there a way to call
[tableView selectRowAtIndexPath: [NSIndexPath indexPathForRow:i inSection:0] animated:NO scrollPosition:UITableViewScrollPositionNone];
without having the currently selected row unselected? I read in documentation, this method does not call delegate's willDeselectRowAtIndexPath.
Here's all code to allow multiple selection. The problem is now that I cannot select programmatically without deselecting previous.
- (NSIndexPath *)tableView:(UITableView *)aTableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary* friend = [friendsData objectAtIndex:[indexPath row]];
if (![selectedIndexes containsObject:friend]) {
[selectedIndexes addObject:friend];
}
else {
[selectedIndexes removeObject:friend];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
return nil;
}
return indexPath;
}
- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary* friend = [friendsData objectAtIndex:[indexPath row]];
if (![selectedIndexes containsObject:friend]) {
return indexPath;
}
// do not select so we can have multiple select
return nil;
}
You'll have to change your data source to reflect the select all or select none, then refresh the rows in question to update them to their new status.
I can't post any specific code because it really depends on how you've set up your multi-selection.
Edit
It seems that you can select all by setting selectedIndexes to friendsData and select none by clearing the contents of selectedIndexes.
Select All:
[selectedIndexes setArray: friendsData];
Select None:
[selectedIndexes removeAllObjects];
Then you can reload your table view. If you want it to be instant, execute [tableView reloadData] otherwise you can use the reload methods with animation.
Here is method to traverse a table, it works well.
Select all the cells in UITableView
for (int i = 0; i < [ptableView numberOfSections]; i++) {
for (int j = 0; j < [ptableView numberOfRowsInSection:i]; j++) {
NSUInteger ints[2] = {i,j};
NSIndexPath *indexPath = [NSIndexPath indexPathWithIndexes:ints length:2];
UITableViewCell *cell = [ptableView cellForRowAtIndexPath:indexPath];
//Here is your code
}
}

insertRowsAtIndexPaths Doesnot call cellForRowAtIndexPath

I created sample tableview application and I have an add button above the tableview, when user pressed the add button only we want to add row to table view.
I am write code like this
- (void)viewDidLoad {
isEditing = NO;
Mutarray = [[NSMutableArray alloc]init];
[super viewDidLoad];
}
- (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.
if (isEditing)
return [Mutarray count];
else
return 0;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
[TableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
NSLog(#"Row = %d", indexPath.row);
// Configure the cell...
cell.textLabel.text = [Mutarray objectAtIndex:indexPath.row];
return cell;
}
//When add button pressed
-(IBAction)Add:(id)sender
{
isEditing = YES;
[Mutarray addObject:[NSString stringWithFormat:#"%d",[Mutarray count]]];
NSArray *insertIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:[Mutarray count]-1 inSection:0],
nil];
[self.TableView beginUpdates];
[self.TableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
[self.TableView endUpdates];
}
This code works fine.But problem is my tableview height is 418 , it shows only 10 row as visible. So when the 11 row was added it added in tableview but not calling this cellForRowAtIndexPath function so I'm not able to auto scroll the page... The first 10 row it calls the cellForRowAtIndexPath function.
So what I my doubts is why the cellForRowAtIndexPath function only calls visible rows?
Then how can I auto scroll my tableview?
So what I my doubts is why the
cellForRowAtIndexPath function only
calls visible rows ?
It is so for optimization reasons. If table view had created cells for all its rows it could downgrade performance dramatically. Instead of that table view creates cells only for rows that are visible (and probably a couple more to ensure smooth scrolling) and then reuses them for rows that become visible - so actually you can show hundreds of row with just, say, 10 cell objects - it is a huge save.
Then how can I auto scroll my
tableview ?
You can scroll right after you added a row in your add method:
...
[table endUpdates];
[table scrollToRowAtIndexPath:[insertIndexPaths objectAtIndex:0]
atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
P.S. conventionally method and variable names in objective-c start with lowercase, it is better style to follow that guideline.

Inserting and deleting UITableViewCell at the same time not working

I'm having quite a bit of pain inserting and deleting UITableViewCells from the same UITableView!
I don't normally post code, but I thought this was the best way of showing where I'm having the problem:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 5;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (iSelectedSection == section) return 5;
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//NSLog(#"drawing row:%d section:%d", [indexPath row], [indexPath section]);
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
if (iSelectedSection == [indexPath section]) {
cell.textColor = [UIColor redColor];
} else {
cell.textColor = [UIColor blackColor];
}
cell.text = [NSString stringWithFormat:#"Section: %d Row: %d", [indexPath section], [indexPath row]];
// Set up the cell
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic -- create and push a new view controller
if ([indexPath row] == 0) {
NSMutableArray *rowsToRemove = [NSMutableArray array];
NSMutableArray *rowsToAdd = [NSMutableArray array];
for(int i=0; i<5; i++) {
//NSLog(#"Adding row:%d section:%d ", i, [indexPath section]);
//NSLog(#"Removing row:%d section:%d ", i, iSelectedSection);
[rowsToAdd addObject:[NSIndexPath indexPathForRow:i inSection:[indexPath section]]];
[rowsToRemove addObject:[NSIndexPath indexPathForRow:i inSection:iSelectedSection]];
}
iSelectedSection = [indexPath section];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:rowsToRemove withRowAnimation:YES];
[tableView insertRowsAtIndexPaths:rowsToAdd withRowAnimation:YES];
[tableView endUpdates];
}
}
This code creates 5 sections, the 1st (indexed from 0) with 5 rows. When you select a section - it removes the rows from the section you had previously selected and adds rows to the section you just selected.
Pictorally, when I load up the app, I have something like this:
http://www.freeimagehosting.net/uploads/1b9f2d57e7.png http://www.freeimagehosting.net/uploads/1b9f2d57e7.png
Image here: http://www.freeimagehosting.net/uploads/1b9f2d57e7.png
After selecting a table row 0 of section 2, I then delete the rows of section 1 (which is selected by default) and add the rows of section 2. But I get this:
http://www.freeimagehosting.net/uploads/6d5d904e84.png http://www.freeimagehosting.net/uploads/6d5d904e84.png
Image here: http://www.freeimagehosting.net/uploads/6d5d904e84.png
...which isn't what I expect to happen! It seems like the first row of section 2 somehow remains - even though it definitly gets deleted.
If I just do a [tableView reloadData], everything appears as normal... but I obviously forefit the nice animations.
I'd really appreciate it if someone could shine some light here! It's driving me a little crazy!
Thanks again,
Nick.
Struggled to get this to work. Here's my code to add a row to my tableView:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[tableView beginUpdates];
[dataSource insertObject:[artistField text] atIndex:0];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
[tableView endUpdates];
I seem to remember that numberOfRowsInSection: will get called when you call deleteRows or insertRow, you need to be really careful that the reality numberOfRowsInSection cliams matches your changes. In this case you may want to try moving the iSelectedSection = [indexPath section]; line to after the endUpdates.
I don't remember where I read this but I believe you shouldn't perform table row updates (insertions and deletions) from inside one of the table view delegate functions. I think a better alternative would be to do a performSelectorOnMainThread passing along the necessary information needed to perform the updates as an object. Something like:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// ....
[self performSelectorOnMainThread: #selector(insertRows:)
withObject: someObjectOrNil]; // double check args
}
- (void) insertRows: (NSObject*)someObjectOrNil {
[tableView beginUpdates];
// update logic
[tableView endUpdates];
// don't call reloadData here, but ensure that data returned from the
// table view delegate functions are in sync
}
In the code you posted, your loop index runs from 0 to 4, which suggests that it would delete all of the rows in section 1, and then add five new rows to section 2. Since each section already has a row 0, this would add a second instance of section 2, row 0 to the table.
I would suggest having your loop run from 1 to 4:
for (int i=1; i<5; i++)
{
// ...
}
FYI: This bug seems to have been fixed completely with the 2.2 iPhone update.
Thanks Apple!
Nick.