核心数据:是否适合更新一组多个对象的父/子管理对象上下文?

时间:2015-09-05 09:03:08

标签: ios core-data concurrency merge nsmanagedobjectcontext

我一直在阅读有关在NSManagedObjectContext中使用父级和子级Core Data的一些链接和帖子,但我发现的示例方案只涉及编辑特定属性父上下文中的对象,然后将更改推送到父上下文。

我需要处理的场景有点复杂,我不确定如何管理它:

我在默认上下文中有一组托管对象(主队列中AppDelegate中提供的对象)。我的应用程序定期调用Web服务以检查是否有这些对象的更新。我想在一个单独的线程中执行这些更新,以避免阻止de UI,因此,当它需要调用de服务来请求更新时,我这样做:

    let bundle = NSBundle.mainBundle()
    let modelURL = bundle.URLForResource("MyApp", withExtension: "momd")
    let model = NSManagedObjectModel(contentsOfURL: modelURL!)!

    let psc = NSPersistentStoreCoordinator(managedObjectModel: model)

    let privateContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
    privateContext.persistentStoreCoordinator = psc

    let documentsURL = CoreDataHelper.applicationDocumentsDirectory()
    let storeURL = documentsURL.URLByAppendingPathComponent("MyApp.sqlite")

    let options = [NSMigratePersistentStoresAutomaticallyOption: true]

    var error: NSError? = nil
    let store: NSPersistentStore? = psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options, error: &error)

也就是说,我在私有队列中创建一个新的上下文,并使用自己的新持久性存储协调器和持久存储。

一旦我拥有私人环境,我就会要求更新服务:

[privateContext performBlockAndWait: ^{
        // Call services
        // Create new objects in this private context with
        // the data in services responses
    }];

此时一切都还不错。我有一个" old"在我的主要上下文中的一组对象,以及一个" new"私有上下文中的对象集。我需要用私有对象中的新对象替换主上下文的对象集。这里的问题是:

  1. 主要上下文中的某些对象在私有上下文中不再存在,因此我需要删除它们。
  2. 在私人环境中可能有新的对象在主要环境中不存在,我需要添加它们。
  3. 私有上下文中的对象也可能在主要对象中,但需要更新它们的一些属性。
  4. 我不知道父/子上下文是否可以处理这种更新,或者它们只适合让用户编辑某些对象。这里不是编辑对象的用户,因此我需要避免阻止UI,而且我不仅要修改对象信息,还要删除和添加新对象(如果需要)。

    我对父/子情境有一些疑问:

    1. 子上下文可以在私有队列中吗?主队列中的父上下文可以吗?
    2. 我已经在某处读到了一些关于设置合并策略的内容,但是我没有找到它的使用示例,在使用父/子上下文时可能没有必要设置合并策略?什么时候开始?我在哪里可以找到示例或教程?
    3. 如果我将我的私有上下文设置为主上下文的子项,并且我保存了子私有上下文,那么私有上下文中的对象是否会取代"我想要的主要上下文中的对象? (包括删除私有上下文中不再存在的对象和新的对象)...我的意思是......整个子上下文是否替换整个父上下文?
    4. 保存私有上下文而不是主要上下文的子项,然后清除并重新获取主上下文中的所有新数据会更好吗?
    5. 我需要帮助才能了解其工作原理以及管理我的方案的最佳方式。

      提前致谢。

      列出项目

1 个答案:

答案 0 :(得分:0)

嗯,您应该阅读一些Core Data / iCloud文档并观看一些WWDC视频,以了解基础知识。基本上,当您对背景上下文(或除主要上下文之外的任何上下文)进行更新并保存时,您需要从主上下文调用API以将这些更改合并到主上下文中。

以下是一些代码段:

// Set the moc here because its defined as Lazy it may be initialised to nil already by
                // something!
                let newMoc = NSManagedObjectContext()
                newMoc.persistentStoreCoordinator = persistentStoreCoordinator
                // Set the MergePolicy to prioritise external inputs
                let mergePolicy = NSMergePolicy(mergeType:NSMergePolicyType.MergeByPropertyStoreTrumpMergePolicyType )
                newMoc.mergePolicy = mergePolicy
                managedObjectContext = newMoc

...

/* Loads the required seed data */
    // Usually called on a background thread and therefor we need to process the DidSave notification
    // to merge the changed with the main context so the UI gets updated
    func loadSeedData() {
        //FLOG(" called");

        let bgContext:NSManagedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.ConfinementConcurrencyType)

        // Register for saves in order to merge any data from background threads
        NSNotificationCenter.defaultCenter().addObserver(self, selector:"storesDidSave:", name: NSManagedObjectContextDidSaveNotification, object:bgContext)

        while (persistentStoreCoordinator == nil) {
            //FLOG(@" persistentStoreCoordinator = nil, waiting 5 seconds to try again...");
            sleep(5);
        }

        bgContext.persistentStoreCoordinator = persistentStoreCoordinator


        insertNewWalletDetails(bgContext, name:"Info")

...

bgContext.processPendingChanges()

        do {

            try bgContext.save()

            //FLOG(" Seed data loaded")

        } catch {
            //FLOG("  Unresolved error \(error), \(error?.userInfo)")
        }

...

// We only care if the one we have open is changing
    func registerForStoreChanges(storeCoordinator: NSPersistentStoreCoordinator) {

        //FLOG("registerForStoreChanges called")
        let nc = NSNotificationCenter.defaultCenter()

        nc.addObserver(self, selector: "storesWillChange:", name: NSPersistentStoreCoordinatorStoresWillChangeNotification, object: storeCoordinator)

        nc.addObserver(self, selector: "storesDidChange:", name: NSPersistentStoreCoordinatorStoresDidChangeNotification, object: storeCoordinator)

        nc.addObserver(self, selector: "storesDidImport:", name: NSPersistentStoreDidImportUbiquitousContentChangesNotification, object: storeCoordinator)

    }

...

// NB - this may be called from a background thread so make sure we run on the main thread !!
    // This is when transaction logs are loaded
    func storesDidSave(notification: NSNotification!) {

        // Ignore any notifications from the main thread because we only need to merge data
        // loaded from other threads.
        if (NSThread.isMainThread()) {
            //FLOG(" main thread saved context")
            return
        }

        NSOperationQueue.mainQueue().addOperationWithBlock {
            //FLOG("storesDidSave ")
            // Set this so that after the timer goes off we perform a save
            // - without this the deletes don't appear to trigger the fetchedResultsController delegate methods !
            self.import_or_save = true

            self.createTimer()
            if let moc = self.managedObjectContext {
                moc.mergeChangesFromContextDidSaveNotification(notification)
            }

        }
    }

对于工作示例应用和其他说明,请查看enter link description here