Chr*_*nce 5 core-data nsfetchedresultscontroller ios
我已经找到了解决这个问题的方法,但我不太喜欢这个解决方法。我的问题是这样的。我正在使用 aNSFetchedResultsController来填充 UICollectionView——它显示图像集合。每个图像由核心数据对象描述(例如,其文件名在核心数据对象中)。
我有一个 UI 控件,允许用户同时删除多个图像,并且当用户删除多个对象时遇到问题。执行删除操作的代码是:
for image in images {
CoreData.sessionNamed(CoreDataExtras.sessionName).remove(image)
}
CoreData.sessionNamed(CoreDataExtras.sessionName).saveContext()
Run Code Online (Sandbox Code Playgroud)
(其中一些是我的库代码)。删除两个对象后,我收到崩溃和以下日志消息:
CoreData:错误:严重的应用程序错误。在核心数据更改处理期间捕获异常。这通常是 NSManagedObjectContextObjectsDidChangeNotification 观察者内的错误。无效更新:第 0 节中的项目数无效。更新后现有节中包含的项目数 (99) 必须等于更新前该节中包含的项目数 (101),加上或减去该数字从该部分插入或删除的项目数(0 插入,1 删除)以及加上或减去移入或移出该部分的项目数(0 移入,0 移出)。与用户信息(空)
如果我将删除代码更改为:
for image in images {
CoreData.sessionNamed(CoreDataExtras.sessionName).remove(image)
CoreData.sessionNamed(CoreDataExtras.sessionName).saveContext()
}
Run Code Online (Sandbox Code Playgroud)
我猜问题是在委托回调方法中:
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
Run Code Online (Sandbox Code Playgroud)
我愿意:
collectionView.deleteItems(at: [indexPath])
Run Code Online (Sandbox Code Playgroud)
显然,您可以在方法中执行 reloadItems didChangeObject,也可以在每次删除对象后执行 saveContext。
如果您删除多个图像,然后保存上下文,FRC 会处理所有删除内容 - 因此其sections、fetchedObjects等会反映所有这些更改。但随后它会didChangeObject:为每个更改单独调用委托方法。在该方法中,您调用 collectionView 更新方法(例如deleteItems);然后,collectionView 调用其 dataSource 方法并进行快速统计:有 X 个项目,Y 个项目被删除,现在有 Z 个项目并抛出错误,因为 Z != XY。
当 FRC 与 tableView 一起使用时,可以通过使用 tableViewbeginUpdates并endUpdates调用 FRCcontrollerWillChangeContent:和controllerDidChangeContent:委托方法来克服此问题。这会导致 tableView 推迟进行统计,直到处理完所有单独的更改 - 此时数字就会累加。
您的解决方案 - 在每次删除后调用saveContext- 导致 FRC 依次处理每个删除:更新其sections、fetchedObjects等,以一次仅反映一个删除。这使 FRC 的数据与 collectionView 保持同步。一种可能的改进是processPendingChanges在每次删除后调用上下文,而不是保存上下文。这可以避免在您可能不想保存数据时保存数据,但仍然会导致每次删除都单独处理。
另一种方法是模仿 tableView 的 beginUpdates/endUpdates 机制来保存所有 collectionView 更新,直到处理完所有 FRC 更新。其工作原理大致如下:
didChangeObject:调用时,将对应的indexPath添加到相关数组中。controllerDidChangeContent:,迭代数组(首先删除,插入时),调用相应的 collectionView 更新方法。(然后清空数组,为下一批更新做好准备)。这个问题及其答案中包含一些很好的解释和潜在的实现。
| 归档时间: |
|
| 查看次数: |
708 次 |
| 最近记录: |