Core Data 我需要在哪里调用 save 方法

ata*_*asa 1 core-data nsmanagedobject nsmanagedobjectcontext swift

我正在使用核心数据,但我对NSManagedObjectContext. 我使用以下代码来保存我的图书数据。书籍数据保存在我的应用程序扩展一侧,如下所示。扩展侧代码块的调用方式与主线程不同,如图所示。 在此输入图像描述

我想知道这是否会因为滥用我的上下文而导致问题?

func saveBook() {
    let book: Book = Book(context: viewContext)
    let uuid = UUID()
    book.sessionId = uuid
    book.appId = session.appId
    book.startedAt = session.startedAt
    book.createdBy = AppData.installId

    coreData.saveSync()
}

func saveSync() {
        let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        privateContext.parent = viewContext
        privateContext.perform {
            do {
                try privateContext.save()
                viewContext.performAndWait {
                    do  {
                        try viewContext.save()
                    } catch {
                        let nsError = error as NSError
                        print("Unresolved error \(nsError), \(nsError.userInfo)")
                    }
                }
            } catch {
                let nsError = error as NSError
                print("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

cgo*_*ijo 6

我在您的代码中看到两个问题:

  1. saveSync 函数中的 privateContext 是 ponintless,因为新的 Book 对象是在 mainContext 中创建的。因此,当您保存 privateContext 时,您将保存一个没有任何更改的空上下文。

  2. 如果我理解得很好,您的 saveBook() 函数正在后台线程中执行,并且您正在使用 mainContext,它始终与主线程关联。

在多线程环境中处理 Core Data 时,您需要记住以下规则:切勿在分配给您的上下文的队列/线程之外的队列/线程中使用 NSManagedObjectContext 或 NSManagedObject,否则您会得到意外的结果,并且您的应用程序将在某个时刻崩溃。

因此,要解决这两个问题,您可以执行以下操作:

func saveBook() {
    let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    privateContext.parent = viewContext
    privateContext.perform {
        let book: Book = Book(context: privateContext)
        let uuid = UUID()
        book.sessionId = uuid
        book.appId = session.appId
        book.startedAt = session.startedAt
        book.createdBy = AppData.installId
        
        do {
            try privateContext.save()
            viewContext.performAndWait {
                do  {
                    try viewContext.save()
                } catch {
                    let nsError = error as NSError
                    print("Unresolved error \(nsError), \(nsError.userInfo)")
                }
            }
        } catch {
            let nsError = error as NSError
            print("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,当您保存 privateContext 时,数据不会持久保存到持久存储中,而是“保存”到其父上下文中。并且只有在mainContext被保存时才会被持久化。这就是为什么您需要在创建 Book 对象后保存这两个上下文。

如果您的类或结构中有 persistenceStoreContainer,您可以使用以下方法创建后台上下文并保存它:

func saveBook() {
    let privateContext = persistentStoreContainer.newBackgroundContext()
    privateContext.perform {
        let book: Book = Book(context: privateContext)
        let uuid = UUID()
        book.sessionId = uuid
        book.appId = session.appId
        book.startedAt = session.startedAt
        book.createdBy = AppData.installId

        do {
            try privateContext.save()
        } catch {
            let nsError = error as NSError
            print("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的好处是,当您保存 privateContext 时,数据会被持久化,因为它的父级是 persistenceStoreCoordinator。

编辑:

这是从持久容器创建后台上下文的另一种方法:

func saveBook() {
    persistentStoreContainer.performBackgroundTask { context in
        let book: Book = Book(context: privateContext)
        let uuid = UUID()
        book.sessionId = uuid
        book.appId = session.appId
        book.startedAt = session.startedAt
        book.createdBy = AppData.installId

        do {
            try context.save()
        } catch {
            let nsError = error as NSError
            print("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)