开发者

UITableView crash when updating cells that change sections

I have a table that displays data from a single array and organizes the items into separate sections based on a set of filters. Each filter has a corresponding section. My UI allows the user to tap a check box embedded in each table cell. This check box sets a "checked" flag which affects which section the item is filtered to. Here's an example:

  • Section 1
    • Item A
    • Item B
  • Section 2
  • Section "Done"

Tapping the check box next to Item A should cause the table to rearrange to look like this:

  • Section 1
    • Item B
  • Section 2
  • Section "Done"
    • Item A

Below is my code for responding to the check box tap. It figures out which row the check box belongs to and then attempts to create an animation block that deletes the row from its old section and adds a row to the end of the "Done" section. Please keep in mind that the array doesn't actually change -- the way the data is filtered into the sections changes based on the value of the items' checked properties.

- (IBAction)checkBoxTapped:(id)sender
{
 // Get the table cell
 CheckBoxControl* checkBox = (CheckBoxControl*)sender;

 UITableViewCell* cell = (UITableViewCell*)[[sender superview] superview];
 UITableView* table = (UITableView*)[cell superview];
 NSIndexPath* indexPath = [table indexPathForCell:cell];

 Item* item = [self itemAtRow:[indexPath row] inSection:[indexPath section]];
 item.checked = checkBox.checked;

 Filter* filter = [filters objectAtIndex:DONE_INDEX];
 // We want the new row at the bottom of the "Done" section.
 NSIndexPath* newIndexPath = [NSIndexPath indexPathForRow:[self countItemsWithFilter:filter] inSection:DONE_INDEX];

 [table beginUpdates];
 [table insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
 [table deleteRowsAtIndexPaths:[NSArray arrayWithObjec开发者_如何学Ct:indexPath] withRowAnimation:UITableViewRowAnimationFade];
 [table endUpdates];
}

This code always throws an exception:

2010-01-13 00:19:44.802 MyApp[19923:207] *** Terminating app due to uncaught
exception 'NSRangeException', reason:
'*** -[NSMutableIndexSet addIndexesInRange:]:Range {2147483647, 1}
exceeds maximum index value of NSNotFound - 1'

Can anyone help me figure out what is causing the NSRangeException? Here's my stack:

___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___
obj_exception_throw
+[NSException raise:format:arguments:]
+[NSException raise:format:]
-[NSMutableIndexSet addIndexesInRange:]
-[NSMutableIndexSet addIndex:]
-[_UITableViewUpdateSupport(Private) _computeRowUpdates]
-[_UITableViewUpdateSupport initWithTableView:updateItems:oldRowData:oldRowRange:newRowRange:context:]
-[UITableView(_UITableViewPrivate) _updateWithItems:withOldRowData:oldRowRange:newRowRange:context:]
-[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:]
-[UITableView endUpdates]
-[RootViewController checkBoxTapped:]

If this code is just plain wrong then how should I animate removing a row from one section and adding it to another?

Thanks in advance for any help you can give me.

-Mike-


Ok, I think I figured out a better approach. Instead of trying to populate the sections using a filtering function I decided to create an array for each section. Each section's array contains indexes into the data source array. It looks something like this:

NSArray* data = [[NSArray alloc] initWithObjects:@"Apple", @"Banana", @"Cat", @"Dog", nil]];
NSMutableArray* doneFilter = [[NSMutableArray alloc] init];
NSMutableArray* othersFilter = [[NSMutableArray alloc] initWithObjects:[NSNumber numberWithInt:0],
                                [NSNumber numberWithInt:1], [NSNumber numberWithInt:2],
                                [NSNumber numberWithInt:3], nil];

Now, when the user taps the checkbox I remove the item's index from the othersFilter and add it to the bottom of the doneFilter. I then remove and add the corresponding rows in the table view. This seems much more stable than what I had before (no exceptions thrown!!) and has the added benefit of allowing the filters to have ordering of their own.


Calling -insertRowsAtIndexPaths and -deleteRowsAtIndexPaths you only tell UITableView to update corresponding rows with animation. So the possible problem is that you should also update your data source accordingly to your changes (e.g. -numberOfRowsInSection must return the actual values etc.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜