Core data UITableView由两个NSFetchedResultsController驱动,结果相同
我实现了一个UITableViewController,其UITableView由两个NSFetchedResultsController的结果驱动(一个表有两个部分,每个NSFetchedResultsController一个部分),如前所述 如果两个NSFetchedResultsController不共享任何共同的结果,则我的代码将正确无误地运行 但是,当我插入一个核心数据对象时,我遇到了这个问题,该对象作为结果显示在我的两个NSFetchedResultsController中:Core data UITableView由两个NSFetchedResultsController驱动,结果相同,core-data,uitableview,nsfetchedresultscontroller,nsfetchrequest,Core Data,Uitableview,Nsfetchedresultscontroller,Nsfetchrequest,我实现了一个UITableViewController,其UITableView由两个NSFetchedResultsController的结果驱动(一个表有两个部分,每个NSFetchedResultsController一个部分),如前所述 如果两个NSFetchedResultsController不共享任何共同的结果,则我的代码将正确无误地运行 但是,当我插入一个核心数据对象时,我遇到了这个问题,该对象作为结果显示在我的两个NSFetchedResultsController中: 严重的
严重的应用程序错误。从的代理捕获到异常
调用-controllerDidChangeContent:期间的NSFetchedResultsController:。
无效更新:节0中的行数无效。中包含的行数
更新(1)后的现有节必须等于包含的行数
在更新(1)之前的部分中,加上或减去插入的行数或
从该节中删除(插入1,删除0)。带userInfo(空)
每当我被要求输入一个节中的行数时,我都会输出:
-(NSInteger)表视图:(UITableView*)表视图行数节:(NSInteger)节{
id sectionInfo;
如果(节<[self.fetchedResultsController 1.sections count]){
sectionInfo=[[self.fetchedResultsController1 sections]objectAtIndex:section];
}
否则{
sectionInfo=[[self.fetchedResultsController2 sections]objectAtIndex:section-[self.fetchedResultsController1.sections count]];
}
NSLog(@“第%d节,第%d行)”,第[sectionInfo numberOfObjects]节;
返回[sectionInfo numberOfObjects];
}
并在对象插入时打印出来:
-(void)控制器:(NSFetchedResultsController*)控制器didChangeObject:(id)索引路径中的一个对象:(NSIndexPath*)变更类型的indexPath:(NSFetchedResultsChangeType)类型newIndexPath:(NSIndexPath*)newIndexPath{
UITableView*tableView=self.tableView;
开关(类型){
案例NSFetchedResultsChangesInsert:
NSLog(@“插入%@%@”、newIndexPath、anObject);
[tableView InsertRowsatindExpath:[NSArray arrayWithObject:newIndexPath]带RowAnimation:UITableViewRowAnimationFade];
打破
案例NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]和RowAnimation:UITableViewRowAnimationFade];
打破
案例NSFetchedResultsChangeUpdate:
[self-configureCell:[tableView cellForRowAtIndexPath:indexPath]atIndexPath:indexPath];
打破
案例NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]和RowAnimation:UITableViewRowAnimationFade];
//重新加载节将插入新行,并确保标题得到适当更新。
[tableView重新加载节:[NSIndexSet IndexSetWithiIndex:NewIndexXPath.section]带RowAnimation:UITableViewRowAnimationFade];
打破
}
}
当我使用上面的代码运行时,我得到以下输出(为了清楚起见,缩写为),上面的错误立即如下所示:
2012-03-28 00:59:55.611 MyApp[517:207]第1节,第0行
2012-03-28 00:59:55.612 MyApp[517:207]第0节第0行
2012-03-28 00:59:55.613 MyApp[517:207]插入两个索引[0,0](实体:MyClass;id:0xd611d50;数据:{
....
})
2012-03-28 00:59:55.614我的应用程序[517:207]第0节有一行
2012-03-28 00:59:55.614 MyApp[517:207]第1节第0行
2012-03-28 00:59:55.618 MyApp[517:207]插入两个索引[0,0](实体:MyClass;id:0xd611d50;数据:{
....
})
2012-03-28 00:59:55.619我的应用程序[517:207]第0节有一行
2012-03-28 00:59:55.620我的应用程序[517:207]第1节和第1排
2012-03-28 00:59:55.620 MyApp[517:207]***在-[UITableView\u endCellAnimationsWithContext:],/SourceCache/UIKit\u Sim/UIKit-1448.89/UITableView.m:995中断言失败
2012-03-28 00:59:55.621 MyApp[517:207]严重的应用程序错误。在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托捕获到异常。无效更新:节0中的行数无效。更新(1)后现有节中包含的行数必须等于更新(1)前该节中包含的行数,加上或减去从该节中插入或删除的行数(插入1,删除0)。带userInfo(空)
让两个NSFetchedResultsController驱动一个结果可能重叠的UITableView不是一个好主意吗?这是一个可以接受的答案,但如果可能的话,我可以做些什么来避免这个错误?我假设您将在
控制器:didChangeObject:…
中发生的更改包装在[tableView BeginUpdate]
和[tableView EndUpdate]中
调用相应的NSFetchedResultsControllerDelegate
方法
因此,每个NSFRC将调用beginUpdate
,insertCells
,以及endUpdates
。按这个顺序
最有可能的问题是,在第一次调用endUpdates
后,tableView请求节数和每个节的行数。此时,在一个部分中,单元格的数量与tableView:numberofrowsinssection:
的结果相匹配。不幸的是,它在另一节中不匹配,因为第二个fetchedResultsController没有执行其委托方法。因此,第二个NSFRC还不能插入新的单元格,但它已经返回了新数量的对象
那么如何解决这个问题呢。我可以想出三种不同的方法。第一个是最好的,最后一个根本不应该做
选项1:重写数据模型,使一个NSFetchedResultsController可以为您工作。只要把你用来决定2个NSFR中哪一个的属性放进去就行了
if (change will cause insert or delete in both sections) {
if (!delayEndUpdates) {
self.delayEndUpdates = YES
self.firstUpdatingController = controller;
[tableView beginUpdates]; // another beginUpdates should stop the tableView from updating. At least in theory
}
}
else {
self.delayEndUpdates = NO;
}
[tableView endUpdates]; // the original
if (self.firstUpdatingController != controller) {
// after the second NSFRC did change its content
if (delayEndUpdates) {
[tableView endUpdates]; // another one to start tableView updating again
}
self.firstUpdatingController = nil;
}