【问题标题】:attempt to recursively call -save: on the context aborted when saving Core Data viewContext after CloudKit Record Changed尝试递归调用 -save: 在 CloudKit 记录更改后保存核心数据 viewContext 时中止的上下文
【发布时间】:2018-03-05 14:55:06
【问题描述】:

在我的应用程序中,当 operation.recordChangedBlock {} 内的 func fetchZoneChanges(database: CKDatabase, databaseTokenKey: String, zoneIDs: [CKRecordZoneID], completion: @escaping () -> Void) 完成后,我使用从 CloudKit 收到的新名称值更新我的 Core Data 数据库中的 coreData 记录。

当我尝试保存上下文时出现错误尝试递归调用 -save: on the context aborted

  func updateCoreDataRecord(editedRecord: Record, newName: String, handleComplete_RecordEditedInCoreData:(()->())) {

        let record_RecordID =  editedRecord.recordID!

        let request: NSFetchRequest<Record> = Record.fetchRequest()
        request.predicate = NSPredicate(format: "recordID = %@", record_RecordID)

        do {
            let results = try self.viewContext?.fetch(request)                
            if results?.count == 1 {
                let recordToUpdate = results![0]
                recordToUpdate.setValue(newName, forKey: "name")
                DispatchQueue.main.async { // Here I receive the error when editing goes from CloudKit
                    self.saveViewContext()
                }
                handleComplete_RecordEditedInCoreData()
            }
        } catch  {
            print(error)
        }

}

以下是其他相关功能:

func saveViewContext() {
        let context = self.getViewContext()
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }

 func getViewContext() -> NSManagedObjectContext {
        return self.persistentContainer.viewContext
    }

我的应用程序中的所有viewContext 调用都是在主线程中进行的。我想这可能会导致错误。

错误导致saveViewContext方法。我不确定,但我认为这可能是一个并发问题,但我不知道如何解决。

在获取 CloudKit Record 更新时,我应该如何重写我的代码以避免此错误?我试图包装所有调用以在主队列上运行,但这没有帮助。

我也在使用相同的updateCoreDataRecord() 方法,当用户更改设备上的 Core Data 记录并且这不会导致错误。当我在 operation.recordChangedBlock {} 中接收来自 CloudKit 的记录更改时,我只会收到此错误,我在其中为记录进行核心数据更新。

【问题讨论】:

标签: ios swift core-data cloudkit nsmanagedobjectcontext


【解决方案1】:

我也陷入了这个错误。来自错误的堆栈跟踪不是很有帮助,以及来自当时运行的所有线程的完整堆栈跟踪。

如果你传递coredata concurrency debug参数被搞,你可以马上发现问题:

-com.apple.CoreData.ConcurrencyDebug 1

在我的情况下,原因是:在某个后台线程上,我正在访问与另一个线程绑定的数据库。我一修复不正确的线程使用,我的问题就消失了。

【讨论】:

    【解决方案2】:

    这是一个老问题,我知道,但我刚刚遇到了这个问题。就我而言,我有一个NSFetchedResultsController 监听数据存储的更改(它在保存时触发)。该控制器设置了一些同步事件,这些事件要求获取一些NSManagedObjects,然后调用.save() 以准备随后调用.refresh(_:mergeChanges:)。所有这一切,似乎与最初的 .save() 调用在同一个运行循环中。

    虽然间接地,我递归地调用.save()!不知何故,我的应用程序像这样顺利运行了一段时间,但我刚刚遇到了它自己循环的一个条件。我通过向我的核心数据包装器的 save() 方法添加一个 ivar 和一个检查来修复它,该方法跟踪它当前是否处于保存操作中(也与 .performAndWait(_:) 结合使用),如果是则返回。

    不管这个叙述对你有没有帮助,我希望当这个问题再次出现时,它至少对我未来的自己和 Google 员工有帮助!

    【讨论】:

      【解决方案3】:

      这个方法是在主线程上触发的吗?如果没有,如果您在 viewContext 上工作,则需要将所有核心数据工作移至主线程,而不仅仅是保存。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多