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.

Answers


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.


Need Your Help

Animate a StatusBarItem when its DataContext changes

c# wpf xaml blend

I would like to animate a StatusBarItem whenever its text is updated, the VisualState is fine and plays if for instance I trigger it during a MouseEnter event; however I can't get it to play during

Java Change Volume OSX

java macos volume osx-mavericks

I am trying to change the volume on my mac running OSX Mavericks. I am currently using this code: