【问题标题】:UITableView crash when updating cells that change sections更新更改部分的单元格时 UITableView 崩溃
【发布时间】:2010-01-13 08:45:26
【问题描述】:

我有一个表格,它显示来自单个数组的数据,并根据一组过滤器将项目组织到单独的部分中。每个过滤器都有一个相应的部分。我的 UI 允许用户点击嵌入在每个表格单元格中的复选框。此复选框设置一个“选中”标志,该标志会影响项目被过滤到的部分。这是一个例子:

  • 第 1 节
    • 项目 A
    • B 项
  • 第 2 节
  • “完成”部分

点击项目 A 旁边的复选框应该会使表格重新排列,如下所示:

  • 第 1 节
    • B 项
  • 第 2 节
  • “完成”部分
    • 项目 A

下面是我响应复选框点击的代码。它确定复选框属于哪一行,然后尝试创建一个动画块,从其旧部分中删除该行并在“完成”部分的末尾添加一行。请记住,数组实际上并没有改变——数据被过滤到部分的方式会根据项目的选中属性的值而改变。

- (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 arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
 [table endUpdates];
}

这段代码总是抛出异常:

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'

谁能帮我找出导致 NSRangeException 的原因?这是我的堆栈:

___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:]

如果这段代码完全错误,那么我应该如何动画化从一个部分中删除一行并将其添加到另一个部分?

提前感谢您能给我的任何帮助。

-迈克-

【问题讨论】:

    标签: iphone uitableview


    【解决方案1】:

    好的,我想我想出了一个更好的方法。我决定为每个部分创建一个数组,而不是尝试使用过滤函数填充这些部分。每个部分的数组都包含数据源数组的索引。它看起来像这样:

    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];
    

    现在,当用户点击复选框时,我会从 othersFilter 中删除项目的索引并将其添加到 doneFilter 的底部。然后我在表格视图中删除并添加相应的行。这似乎比我以前的稳定得多(没有抛出异常!!),并且具有允许过滤器自己排序的额外好处。

    【讨论】:

      【解决方案2】:

      调用-insertRowsAtIndexPaths-deleteRowsAtIndexPaths 只会告诉 UITableView 用动画更新相应的行。所以可能的问题是您还应该根据您的更改更新数据源(例如,-numberOfRowsInSection 必须返回实际值等)

      【讨论】:

      • 我写了 -numberOfRowsInSection 来询问该部分的过滤器有多少项目匹配。在调用 -insertRowsAtIndexPaths 和 -deleteRowsAtIndexPaths 之前更改项目的“已检查”属性,因此过滤器将报告每个部分的正确项目数。我在 -numberOfRowsInSection 中放置了一个断点并验证了这一点。我设计了数据源,因此不会修改数组。每个部分都显示来自同一数组副本的项目,过滤器根据项目的值确定每个部分显示的项目。这有意义吗?
      • 没有。当我尝试时,我每次都会遇到异常。我正在测试环境中尝试其他一些方法,看看是否可以缩小范围。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多