如何正确使用Core Data managedObjectContext以及保存上下文的正确方法?

时间:2018-05-30 09:51:41

标签: ios swift core-data concurrency nsmanagedobjectcontext

在我的应用中,我有一个特殊的 CoreDataManager 类,负责我的应用中的所有Core Data操作。

CoreDataManager 类中的第一行如下所示:

   static var sharedInstance: CoreDataManager = { // or private static var
        let instance = CoreDataManager()
        return instance
    }()

    // Init
    override init() {
        self.persistentContainer = NSPersistentContainer.init(name: "AppName")
        self.persistentContainer.loadPersistentStores { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("CoreDataManager: init, loadPersistentStores error: \(error), \(error.userInfo)")
            } else {
                print("CoreDataManager: init() func finished with Success!")


            }
        }

        self.persistentContainer.viewContext.undoManager = nil 
        self.persistentContainer.viewContext.shouldDeleteInaccessibleFaults = true
        self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true

    }

    let persistentContainer: NSPersistentContainer
    var viewContext: NSManagedObjectContext? {
        return self.persistentContainer.viewContext
    }


    func saveViewContext() {

        let context = self.viewContext

        if self.viewContext != nil {

            if context!.hasChanges {
                do {
                    try context!.save()

                } catch {

                    let nserror = error as NSError
                    fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                }

            }


        }

当我需要在我的应用程序中保存,编辑或删除核心数据实体时,我会调用 CoreDataManager 类的单例,以及在此类中声明的(保存,编辑,删除实体)方法。

在我的应用中,我还有 LocalNotificationManager ,当我从CoreData收到更改或删除某些实体时,我会在CloudKit个实体中执行一些操作。当我想保存更改时,我正在调用CoreDataManager.sharedInstance.saveViewContext(),并且“认为我做错了,因为有时我会遇到错误。

我不清楚如何正确调用上下文并保存它,并提出以下问题:

在我的保存,编辑,删除通话中,我应该使用/保存 mainContext 还是 privateContext

收到通知后,我应该使用/保存 mainContext 还是 privateContext

何时应该从主线程保存viewContext,何时使用私有托管对象上下文?我应该使用 .MainQueueConcurrencyType 还是我可以避免它?

我应该在 CoreDataManager 类中声明 privateObjectContext 变量,这是正确的方法吗?

我已经看到私有上下文可以通过这种方式声明,但我可以在 CoreDataManager 类中实现它,何时应该调用它而不是saveViewContext()

 let moc = NSManagedObjectContext(concurrencyType:.MainQueueConcurrencyType)
 let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
 privateMOC.parentContext = moc
 privateMOC.performBlock({
     do {
         try privateMOC.save()
     } catch {
         fatalError("Failure to save context: \(error)")
     }
     })

任何人都可以清楚地解释在不同情况下保存上下文的正确用法吗?

Swift 4,Xcode 9。

1 个答案:

答案 0 :(得分:1)

您有两种选择:

简单方法

仅对viewContext进行读写,并且仅从主线程进行读写。这将有效但如果您有大量数据,您一次正在阅读或写入,它将阻止您的用户界面。如果你有一个应用程序,核心数据中存储了少量的东西,这将工作正常,是迄今为止最简单的选项。

复杂的方式

使用viewContext完成所有阅读,但绝不写入。仅从主线程访问viewContext。使用persistentContainer.performBackgroundTask完成所有写作并使用传递给块的上下文。不要在此块中使用任何其他managedObject。如果你需要传递一个objectId并在块内进行一次获取。不要在这些街区之外传递任何物体。如果您发现需要,则使用objectId。您还需要创建一个operationQueue并将所有调用包装到其中performBackgroundTask,这样您就不会发生任何写入冲突。