我有多个核心数据实体,都同步到服务器。为了测试我已经构建了一个函数,它将: 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")
}
}
答案 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此幻灯片的显示位置: 我尝试过使用.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()
}