NSFetchedResultsController无法识别删除

时间:2017-04-25 12:30:11

标签: ios swift core-data nsfetchedresultscontroller

我有多个核心数据实体,都同步到服务器。为了测试我已经构建了一个函数,它将: 1.删​​除所有核心数据实体 2.调用API刷新所有数据

     // Next delete data in all entities (but not user)
    for entity in CoreDataStack.sharedInstance.allEntities() {
        if (entity != "User") {
            if (DataAccess.deleteExisting(entityName: entity, inMoc: self.operationMOC)) {
                print("Deleted OK: \(entity)")
            } else {
                print("ERROR deleting \(entity)")
            }
        }
    }

    ....

    // Save updates
    self.operationMOC.performAndWait {
        do {
            try self.operationMOC.save()
        } catch {
            fatalError("ERROR: Failed to save operation moc: \(error)")
        }
    }
    self.mainThreadMOC.performAndWait {
        do {
            try self.mainThreadMOC.save()
        } catch {
            fatalError("ERROR: Failed to save main moc: \(error)")
        }
    }

问题是控制我的UI的NSFetchedResultsController似乎没有识别删除,当“didChange”委托方法为更新触发时发出错误

  

错误:严重的应用程序错误。在Core Data更改处理期间捕获到异常。这通常是NSManagedObjectContextObjectsDidChangeNotification的观察者中的错误。无效更新:第0节中的行数无效。更新后现有部分中包含的行数(14)必须等于更新前该部分中包含的行数(7),加上或减去数字从该部分插入或删除的行(插入1个,删除0个)并加上或减去移入或移出该部分的行数(0移入,0移出)。 with userInfo(null)

我已将刷新功能分成两部分,因此我可以看到删除永远不会被识别,因此当更新触发并尝试使用tableView.insertRows(at:...)时,有太多UITableView行。 我也尝试在主线程上直接更新MOC - 没有运气

我还有一位观察员:

NotificationCenter.default.addObserver(self, selector: #selector(MessagesTab.dataChanged), name: NSNotification.Name.NSManagedObjectContextObjectsDidChange, object: self.mainThreadMOC)

在删除和更新方面完全解雇,因此Core Data正在做它的工作。

因此,在我转储NSFetchResults控制器并使用通知滚动自己之前的问题是,是否有人知道我在这里做错了什么? (无论是代码还是期望) 我在过去的一天都对此感到难过,所以任何建议都会被感激不尽。

我的NSFetchedResultsControllerDelegate didChange方法:

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    print(">>>> FRC Change Fired")
    switch type {
    case .insert:
        tableView.insertRows(at: [newIndexPath!], with: .automatic)
    case .delete:
        tableView.deleteRows(at: [indexPath!], with: .automatic)
    case .update:
        let rowMessage = self.fetchedResultsController.object(at: indexPath!)
        if let cell = self.tableView.cellForRow(at: indexPath!) as? InterestsListCell {
            cell.configureWithData(rowMessage)
        }
    default:
        print("Was not a update, delete or insert")
    }
}

4 个答案:

答案 0 :(得分:1)

非常感谢@JonRose 此代码不会导致FRC触发

    // Delete all records for the entity
    func deleteExisting(entityName: String, inMoc moc: NSManagedObjectContext) -> Bool {
    do {
        let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
        try moc.execute(deleteRequest)
        return true
    } catch {
        print("ERROR: deleting existing records - \(entityName)")
        return false
    }
}

随后我对此进行了研究并希望它能够帮助其他人 - 请参阅WWDC 2015 session on Core Data此幻灯片的显示位置:enter image description here 我尝试过使用.refreshAll()和.mergeChages,但对我来说简单似乎就是放弃我的FRC并使用NSManagedObjectContextDidSave通知

答案 1 :(得分:0)

这是预期的行为,因为@redPanda指出,批处理删除/更新直接在存储上发生。您可以尝试使用

刷新上下文(通常是“主”作为FRC所连接的上下文)。
context.refreshAllObjects()

答案 2 :(得分:0)

我最终将 FRC 清零,然后在批量删除完成后重建它

    fetchedResultsController = nil

    dataProvider?.deleteAllAlertsBatch  { error in
        DispatchQueue.main.async {
            print(" done delete \(error)")
            self.loadSavedData() // <- build the FRC again here - it will find 0 records

        }
    }

答案 3 :(得分:0)

如上所述,NSBatchDeleteRequest 不反映上下文的变化。添加新 FRC 时,取消 FRC 可能会导致更新 UITableView 出现问题。

context.refreshAllObjects() 是要走的路,但要添加到@infinateLoop 的答案中(我无法发表评论):

func deleteAndUpdate() {

    DeleteRecords(moc: context) // your NSBatchDeleteRequest function here

    context.refreshAllObjects()
    try? frc.performFetch() // catch error if required
    myTableView.reloadData()
}