具有多个 NSFetchedResultsControllers 的 UITableView 导致断言失败
Posted
技术标签:
【中文标题】具有多个 NSFetchedResultsControllers 的 UITableView 导致断言失败【英文标题】:UITableView with multiple NSFetchedResultsControllers causing Assertion failure 【发布时间】:2011-01-12 12:16:02 【问题描述】:我有一个包含 3 个部分的 UITableView,每个部分都通过唯一的 NSFetchedResultsController 提供。
在插入、更新...表时,我从 NSFetchedResultsController -controllerDidChangeContent 收到 Assertion failure。
我的猜测是 indexPaths 出现在下面的方法中,因为每个控制器只有一个部分 (0),而对于第 0 部分中的控制器,故障不会发生。
- (void)controller:(NSFetchedResultsController*)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath*)newIndexPath
switch(type)
case NSFetchedResultsChangeInsert:
[[self atableView] insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
break;
case NSFetchedResultsChangeDelete:
[[self atableView] deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(DashboardViewCell *) [[self atableView] cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[[self atableView] deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[[self atableView] insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
所以我的问题是,如何确定正在处理哪个控制器(来自哪个部分)并相应地修改 indexPath 以及这样做是否正确?可能还有使用多个 nsfetchedresultscontroller 和一个 uitableview 的任何示例。
【问题讨论】:
【参考方案1】:所以我的猜测实际上是正确的:
随着每个控制器进入以下功能
(void)controller:(NSFetchedResultsController*)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath*)newIndexPath除了为第 0 节设置的控制器之外,每个控制器的 indexPath 都不正确。
每个控制器只有一个部分 - 在我的例子中为 0,但更重要的是,这些部分与表格部分不对应。
所以我目前实现的解决方法(不是很好,所以可能会返工)是检查控制器的 cacheName 并在此基础上修改 indexPath/newIndexPath 部分
类似这样的:
if([[controller cacheName] isEqualToString:@"sectionX"])
indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:<add correct section>];
newIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:<add correct section>];
【讨论】:
感谢您节省时间 ;)newIndexPath
的一个小错误。应该是[NSIndexPath indexPathForRow:newIndexPath.row inSection:<add correct section>]
【参考方案2】:
我不确定它是 FetchedResultController。
insert 和 delete 行调用会在某些时候要求 tableView 重新加载,然后它会要求 numberOfRowsInSection、cellForRowAtIndexPath 等的委托和数据源方法。
可能发生的情况是模型和 tableView 不同步,导致控制器抛出警告。
[tableView beginUpdates];
if (editingStyle == UITableViewCellEditingStyleDelete)
NSMutableDictionary *item = [self.itemList objectAtIndex:indexPath.row];
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.itemList removeObjectAtIndex:indexPath.row];
[tableView endUpdates];
尝试这样的事情,其中对 tableView 和底层模型的所有更改都包含在 beginUpdates 和 endUpdates。这些将导致 tableView 等待单元格的绘制,直到您给出“确定”。
如果不是上述情况,这里是我通常如何处理 tableView 中的多个部分。
在您的标题中,您为这些部分声明一个 typedef 枚举;
typedef enum
SectionTypeName,
SectionTypeAge,
SectionTypeSkills,
SectionType;
//in the implementation
switch (indexPath.section)
case SectionTypeName:
//do thing in the name section
break;
case SectionTypeAge:
//do thing in the name section
break;
case SectionTypeSkills:
//do thing in the name section
break;
default:
break;
我几乎在每个 tableView 委托/数据源方法中都有 switch()。 这样可以很容易地确定正在处理的部分以及它的作用。
【讨论】:
以上是关于具有多个 NSFetchedResultsControllers 的 UITableView 导致断言失败的主要内容,如果未能解决你的问题,请参考以下文章
如何按创建 UITableViewCell 时计算的值对 UITableView 进行排序?
启动 Core Data 应用程序时在后台配置 NSFetchedResultsController
使用多个数据库各自具有一个模式,还是使用一个数据库具有多个模式更好?
将具有多个表的 Access 数据库导出到具有多个工作表的 Excel