尝试递归调用-save:在CloudKit记录更改后保存Core Data viewContext时中止上下文

时间:2017-09-24 15:19:42

标签: ios swift core-data cloudkit nsmanagedobjectcontext

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

  

当我试图保存上下文时,出现错误尝试以递归方式调用-save:on on 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()方法,这不会导致错误。我只是在从operation.recordChangedBlock {}中的CloudKit接收记录更改时才收到此错误,我在其中为记录进行Core Data更新。

3 个答案:

答案 0 :(得分:0)

这个方法是在主线程上触发的吗?如果没有,您需要将所有Core Data工作移动到主线程,如果您正在对viewContext进行操作,而不仅仅是保存。

答案 1 :(得分:0)

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

尽管是间接的,但我递归地调用.save()!不知何故,我的应用程序像这样平稳运行了一段时间,但是我刚刚遇到了一个循环出现的情况。我通过在核心数据包装器的save()方法中添加一个ivar和一个检查项来对其进行修复,该方法可以跟踪它是否当前处于保存操作中(还与.performAndWait(_:)结合使用),并返回是否存在。 / p>

无论这个叙述对您有没有帮助,我希望它至少在以后再次出现此问题时对我自己和Google员工有用!

答案 2 :(得分:0)

我也陷入了这个错误。错误产生的Stacktrace以及当时运行的所有线程的完整stacktrace都没有太大帮助。

如果通过了coredata并发调试参数,则可以立即发现问题:

-com.apple.CoreData.ConcurrencyDebug 1

在我的情况下,原因是:在某个后台线程上,我正在访问与另一个线程绑定的数据库。我一改正错误的线程用法,问题就解决了。