ios - 删除多个核心数据对象 : Issue with NSFetchedResultsController

标签 ios core-data nsfetchedresultscontroller

我已经找到了解决这个问题的方法,但我不太喜欢这个修复方法。我的问题是这样的。我正在使用 NSFetchedResultsController 来填充显示图像集合的 UICollectionView。每个图像都由一个 Core Data 对象描述(例如,它的文件名在 Core Data 对象中)。

我的 UI 控件允许用户同时删除多张图像,但当用户删除多个对象时遇到了问题。执行删除的代码是:

    for image in images {
       CoreData.sessionNamed(CoreDataExtras.sessionName).remove(image)
    }

    CoreData.sessionNamed(CoreDataExtras.sessionName).saveContext()

(其中一些是我的库代码)。 删除两个对象后,出现崩溃并显示以下日志消息:

CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (99) must be equal to the number of items contained in that section before the update (101), plus or minus the number of items inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)

解决问题的方法是,如果我将删除代码更改为:

    for image in images {
        CoreData.sessionNamed(CoreDataExtras.sessionName).remove(image)
        CoreData.sessionNamed(CoreDataExtras.sessionName).saveContext()
    }

我猜问题出在委托(delegate)回调方法中:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath {

我愿意:

collectionView.deleteItems(at: [indexPath]) 

显然,您可以在 didChangeObject 方法中执行 reloadItems,或者在每次删除对象后执行 saveContext。

最佳答案

如果您删除多个图像,然后保存上下文,则 FRC 会处理所有删除 - 因此它的 sectionsfetchedObjects 等会反射(reflect)所有这些更改。但它随后会针对每个更改分别调用 didChangeObject: 委托(delegate)方法。在该方法中,您调用 collectionView 更新方法(例如 deleteItems); collectionView 然后调用它的 dataSource 方法并快速统计:有 X 项,Y 项被删除,现在有 Z 项并抛出错误,因为 Z != X-Y。

当 FRC 与 tableView 一起使用时,可以通过在 FRC controllerWillChangeContent: 中调用 tableView beginUpdatesendUpdates 来解决这个问题和 controllerDidChangeContent: 委托(delegate)方法。这会导致 tableView 推迟计算,直到所有单独的更改都已处理 - 此时数字会加起来。

您的解决方案 - 在每次删除后调用 saveContext - 导致 FRC 依次处理每个删除:更新其 sectionsfetchedObjects、等等,一次只反射(reflect)一个删除。这使 FRC 的数据与 collectionView 保持同步。一种可能的改进是在每次删除后对上下文调用 processPendingChanges,而不是保存上下文。这可以避免在您不想保存数据时保存数据,但仍然会导致每次删除都单独处理。

另一种方法是模仿 tableView 的 beginUpdates/endUpdates 机制来保存所有 collectionView 更新,直到处理完所有 FRC 更新。这大致如下:

  1. 创建数组以跟踪更改(插入、删除)。
  2. 每次调用didChangeObject:时,将相应的indexPath添加到相关数组中。
  3. 当调用 controllerDidChangeContent: 时,遍历数组(先删除,然后插入)调用相应的 collectionView 更新方法。 (然后清空数组,为下一批更新做好准备)。

一些很好的解释和潜在的实现包含在 this question and its answers 中.

关于ios - 删除多个核心数据对象 : Issue with NSFetchedResultsController,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47614583/

相关文章:

iphone - [[NSFetchedResultsController alloc] initWithFetchRequest上的SIGBART

ios - 搜索栏处于事件状态时状态栏图标变黑

ios - 这将是使用 Core Data (iOS) 更新用户 ReadOnly 数据库的最佳方式

ios - 使用 NSPredicate 从 NSFetchedResultscontroller 更新 NSManagedObject 时出现 CoreData 错误

iphone - 我应该在 iPhone 上预先获取所有核心数据实体吗?

ios - SwiftUI:如何将 CoreData 与动态过滤器相加?

ios - UIActivityIndi​​cator 在 NSFetchedResultsController 完成获取之前停止动画

从列表中打开 View 的 Ios 默认图标

java - 将 iOS 应用程序转换为 Android 应用程序

ios - `UINavigationBar` 弯曲扩展?