views:

3151

answers:

1

Hello

We are about to submit an application to the App store and we have encountered a very odd error when deleting rows and sections in a table.

So far, and for compatibility shake we've been linking with 2.0 (so that any iPhone could run our code).

For that scenario, we have a group table that allows removing items and this is how we handle item removal:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
     NSMutableArray* sect = (NSMutableArray*)[tableContents objectAtIndex:indexPath.section];
     [sect removeObjectAtIndex:indexPath.row];
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];

     //if the section is empty remove it
     if ([sect count] == 0){
      [tableContents removeObjectAtIndex:indexPath.section];
      [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
     }

     [tableView reloadData];
    }   
}

This little code works quite well but we have a problem whit section titles. When you delete the last row (the last row left) in a section, that section title remains in the view, floating in the middle of nowhere.

What are we missing?

Thanks in advance

Gonso.

After adding beginUpdate/endUpdates I got a EXC_BAD_ACCES and this output in the console:

#0  0x30beae79 in -[UITableViewRowData rectForFooterInSection:] ()
#1  0x30a9f02d in -[UITableView(_UITableViewPrivate) _updateWithItems:withOldRowData:oldRowRange:newRowRange:] ()
#2  0x30a9a541 in -[UITableView(_UITableViewPrivate) _endCellAnimations] ()
#3  0x0000276a in -[RootViewController tableView:commitEditingStyle:forRowAtIndexPath:] (self=0x5248c0, _cmd=0x30c620b0, tableView=0x528c40, editingStyle=UITableViewCellEditingStyleDelete, indexPath=0x52e6e0) at /Users/MacAdmin/Documents/ws/LabTest/TableViewDeletes/Classes/RootViewController.m:135
#4  0x30a9886c in -[UITableView(UITableViewInternal) animateDeletionOfRowWithCell:] ()
#5  0x30b06d40 in -[UIRemoveControl _doRemove:] ()
#6  0x30a4eee6 in -[UIApplication sendAction:to:from:forEvent:] ()
#7  0x30ab0d36 in -[UIControl sendAction:to:forEvent:] ()
#8  0x30ab11fe in -[UIControl(Internal) _sendActionsForEvents:withEvent:] ()
#9  0x30ab0544 in -[UIControl touchesEnded:withEvent:] ()
#10 0x30a7dc73 in -[UIScrollView touchesEnded:withEvent:] ()
#11 0x30a96a9f in -[UITableView touchesEnded:withEvent:] ()
#12 0x30a67917 in -[UIWindow sendEvent:] ()
#13 0x30a56fff in -[UIApplication sendEvent:] ()
#14 0x30a561e0 in _UIApplicationHandleEvent ()
#15 0x31565dea in SendEvent ()
#16 0x3156840c in PurpleEventTimerCallBack ()
#17 0x9200d615 in CFRunLoopRunSpecific ()
#18 0x9200dcf8 in CFRunLoopRunInMode ()
#19 0x31566600 in GSEventRunModal ()
#20 0x315666c5 in GSEventRun ()
#21 0x30a4eca0 in -[UIApplication _run] ()
#22 0x30a5a09c in UIApplicationMain ()
#23 0x00001fb0 in main (argc=1, argv=0xbfffee88) at /Users/MacAdmin/Documents/wsPogo/LabTest/TableViewDeletes/main.m:14


This is the final code, working if you link for 2.0 ONLY.

if (editingStyle == UITableViewCellEditingStyleDelete) {
    // Delete the row from the data source
     NSMutableArray* sect = (NSMutableArray*)[tableContents objectAtIndex:indexPath.section];
     [sect removeObjectAtIndex:indexPath.row];
     //if its the last row left in the section, just delete the section.
     //if the section is empty remove it
     if ([sect count] == 0){
      [tableContents removeObjectAtIndex:indexPath.section];
      [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
     } else {
      //section is not empty, just remove the row
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
     }
     [tableView reloadData];
}

Thanks!

+1  A: 

I'm not sure if this works on 2.0 since I am using directly 3.0 and now 3.1 beta, but you can try as follows, surrounding your row/section deletions within a beginUpdates/endUpdates block. If this works for you on 2.0, be sure to read the documentation related to these methods to understand exactly what you are allowed to do inside such a block and what is instead strictly forbidden. Note indeed, that I have moved your model updates before the block. Hope this helps.

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        NSMutableArray* sect = (NSMutableArray*)[tableContents objectAtIndex:indexPath.section];
        [sect removeObjectAtIndex:indexPath.row];
        if ([sect count] == 0)
            [tableContents removeObjectAtIndex:indexPath.section];

        [tableView beginUpdates]
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];

        //if the section is empty remove it
        if ([sect count] == 0){
                [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
        }
        [tableView endUpdates]

        [tableView reloadData];
    }   
}
unforgiven
Thanks for the idea, but didn't work at all.Section headers still fly around AND now I get a EXC_BAD_ACCESS when deleting the second and last item on a section.I would like to upload my sample project, so you can see it for yourself. How can I do it?Gonso
gonso
Where in your code is the EXC_BAD_ACCESS generated? Simply using the block I suggested can not cause the problem. Can you post the stack trace obtained using the gdb command bt? Also, what happens if you comment the [tableView reloadData]; line so that it is not executed?
unforgiven
Ok, googling around it seems that 2.0, 2.1 and 2.2 show a different behaviour:http://www.innerexception.com/2009/01/uitableview-numberofrowsinsection.htmlAlso, you may want to try to delete just the section and not the row when deleting the last row in a section. Again this changes from 2.0 to 2.1 and 2.2
unforgiven
Line 1 of your stack trace is where the mismatch in the expected return value of tableView:numberOfRowsInSection: described in http://www.innerexception.com/2009/01/uitableview-numberofrowsinsection.htmlappears. Then, you get the EXC_BAD_ACCESS in line 0.
unforgiven