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

Posted

技术标签:

【中文标题】核心数据:父/子托管对象上下文是不是适合更新一组多个对象?【英文标题】:Core Data: are parent/child Managed Object Contexts appropriate for updating a set of multiple objects?核心数据:父/子托管对象上下文是否适合更新一组多个对象? 【发布时间】:2015-09-05 09:03:08 【问题描述】:

我一直在阅读一些关于在Core Data 中使用父子NSManagedObjectContext 的链接和帖子,但是我发现的示例场景只是在父上下文中编辑某个对象的属性,然后将更改推送到父上下文。

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

我在默认上下文中有一组托管对象(主队列中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
    ];

此时一切正常。我的主要上下文中有一组“旧”对象,而私有上下文中有一组“新”对象。我需要用私有对象中的新对象集替换主上下文的对象集。这里的问题是:

    主上下文中的一些对象在私有上下文中不再存在,所以我需要删除它们。 私有上下文中可能存在主上下文中不存在的新对象,我需要添加它们。 私有上下文中的对象可能也在主上下文中,但需要更新它们的某些属性。

我不知道父/子上下文是否可以处理这种更新,或者它们只适合让用户编辑某些对象。这里不是用户编辑对象,所以我需要避免阻塞 UI,而且我不只是修改对象信息,而是在需要时删除和添加新对象。

我有一些关于父/子上下文的问题:

    子上下文可以在私有队列中,而父上下文可以在主队列中吗? 我在某处读过一些关于设置合并策略的内容,但我没有找到它的使用示例,也许在使用父/子上下文时不需要设置合并策略?什么时候设置?在哪里可以找到示例或教程? 如果我将私有上下文设置为主上下文的子上下文,并保存子私有上下文,那么私有上下文中的对象是否会按照我的意愿“替换”主上下文中的对象? (包括删除不再存在于私有上下文和新上下文中的对象)......我的意思是......整个子上下文是否替换了整个父上下文? 保存私有上下文而不是主上下文的子上下文,然后清除并重新获取主上下文中的所有新数据会更好吗?

我需要帮助来了解其工作原理以及管理我的场景的最佳方式。

提前致谢。

列表项

【问题讨论】:

您应该在主上下文中注册上下文保存通知。然后使用后台线程上的私有上下文执行所有工作。也就是说,使用私有上下文获取远程数据,在该线程上执行搜索、删除、更新和添加 - 请记住,您可以访问主上下文看到的相同数据。一旦完成在私有上下文上调用 moc.save 将触发到主上下文的保存通知,然后调用主上下文合并 API。从主线程执行后一个调用,通知将发布在后台线程上。 @DuncanGroenewald “调用主上下文合并 API”是什么意思? 【参考方案1】:

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

这里有一些代码sn-ps:

// 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

【讨论】:

以上是关于核心数据:父/子托管对象上下文是不是适合更新一组多个对象?的主要内容,如果未能解决你的问题,请参考以下文章

父/子托管对象上下文究竟是如何工作的?

在 Core Data 中执行子获取时,在父上下文中修改托管对象是不是会向下传播到子上下文?

如何“告诉”父上下文必须删除和/或插入哪些托管对象?

CoreData 合并冲突显示托管对象版本更改而不是数据

核心数据 - 2 个对象模型,1 或 2 个托管对象上下文 - 哪个更好?

将子实体加载到核心数据中的托管对象