我找到了解决方法,但我并不喜欢这个修复。我的问题是这样的。我正在使用NSFetchedResultsController
来填充UICollectionView--它显示了一组图像。每个图像由Core Data对象描述(例如,其文件名在Core Data对象中)。
我有UI控件,允许用户同时删除多个图像,并且当用户删除多个对象时出现问题。删除的代码是:
for image in images {
CoreData.sessionNamed(CoreDataExtras.sessionName).remove(image)
}
CoreData.sessionNamed(CoreDataExtras.sessionName).saveContext()
(其中一些是我的图书馆代码)。 删除两个对象后,我收到崩溃和以下日志消息:
CoreData:错误:严重的应用程序错误。抓住了例外 在核心数据更改处理期间。这通常是一个bug NSManagedObjectContextObjectsDidChangeNotification的观察者。 无效更新:第0部分中的项目数无效 更新(99)后现有部分中包含的项目必须是 等于该部分之前包含的项目数 更新(101),加上或减去插入或删除的项目数 从该部分(0插入,1删除)和加号或减号 物品移入或移出该部分(0移入,0移出)。 with userInfo(null)
如果我将删除代码更改为:
,问题是什么? for image in images {
CoreData.sessionNamed(CoreDataExtras.sessionName).remove(image)
CoreData.sessionNamed(CoreDataExtras.sessionName).saveContext()
}
我想问题是在委托回调方法中:
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
我做:
collectionView.deleteItems(at: [indexPath])
显然,您可以在didChangeObject
方法中执行reloadItems,也可以在每次删除对象后执行saveContext。
答案 0 :(得分:1)
如果删除多个图像,然后保存上下文,FRC将处理所有删除 - 因此其sections
,fetchedObjects
等会反映所有这些更改。但是它会针对每个更改单独调用didChangeObject:
委托方法。在该方法中,您调用collectionView更新方法(例如deleteItems
);然后,collectionView调用其dataSource方法并快速计算:有X个项目,Y项目被删除,现在有Z个项目并因为Z!= X-Y而抛出错误。
当FRC与tableView一起使用时,通过在FRC beginUpdates
和endUpdates
委托方法中使用tableView controllerWillChangeContent:
和controllerDidChangeContent:
调用可以解决此问题。这会导致tableView推迟进行计数,直到处理完所有单个更改 - 此时数字会加起来。
您的解决方案 - 在每次删除后调用saveContext
- 导致FRC依次处理每个删除:更新其sections
,fetchedObjects
等,以反映一个删除时间。这使FRC的数据与collectionView保持同步。一种可能的改进是在每次删除后在上下文中调用processPendingChanges
,而不是保存上下文。这可以避免在您可能不希望的情况下保存数据,但仍会导致每个删除都单独处理。
另一种方法是模仿tableView的beginUpdates / endUpdates机制来保存所有的collectionView更新,直到处理完所有FRC更新。这大致如下:
didChangeObject:
时,将相应的indexPath添加到相关数组中。controllerDidChangeContent:
时,遍历数组(首先删除,插入时)调用相应的collectionView更新方法。 (然后清空阵列,为下一批更新做好准备)。this question and its answers中包含了一些很好的解释和潜在的实现。