即使设置了合并策略,保存时也会发生NSConstraint冲突

时间:2019-05-14 03:42:29

标签: swift core-data nsmergepolicy

我有一个核心数据堆栈,该堆栈仅显式使用主上下文,并且仅对context.performAndWait块内的持久对象进行更改/创建。如果我需要背景上下文,请始终使用以下代码块:

persistentContainer.performBackgroundTask()
{context in
    context.performAndWait
    {
        defer
        {
            context.save()
            persistentContainer.context.save()
        }
        //make changes here
    }
} 

主上下文的合并策略是在创建persistentStore时设置的,设置为NSOverwriteMergePolicy,当我保存后台上下文时,我希望可以用在其中创建的任何“新”对象覆盖主上下文上的任何“旧”对象。背景上下文。相反,发生的是我遇到了NSConstraintConflict错误,因为后台上下文使用默认的合并策略(不知道为什么,我希望它继承主上下文的合并策略。)当我显式设置后台上下文的合并策略时,最后我得到的对象是重复对象,根据我设置的约束条件,不应重复这些对象。在这种情况下,clientID属性对于任何给定的Client实体必须是唯一的。

我觉得我不知道如何正确地合并上下文。我现在这样做的方式只是保存背景上下文,然后保存主要上下文,如上所述。但是,如果我没有正确合并,当在后台上下文中创建的对象具有与主上下文中的对象相同的属性时,为什么会发生约束错误?当我在主上下文中执行提取请求时,为什么会出现重复项?

我只用了大约两个月的时间就使用了核心数据,而我所知道的一切都来自文档或此处,所以我确定有些事情我只是一无所知。关于我在做什么错的任何想法吗?

1 个答案:

答案 0 :(得分:0)

结果是,我没有为看到重复的实体设置约束。设置约束摆脱了重复的对象。

为解决每次保存在后台上下文中时NSConstraintConflict错误的问题,我使用以下自定义类使使用的函数创建的所有后台上下文具有相同的合并策略:

class MergePolicedNSPersistentContainer: NSPersistentContainer
{
    override func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void)
    {
        super.performBackgroundTask()
        { context in
            context.mergePolicy = PersistenceManager.shared.mergePolicy
            //PersistenceManager is a custom singleton class where I do lots of custom coreData stuff, mostly sanity checks and locks. In this case I use it to store a merge policy instance to use here.
            block(context)
        }
    }
}

在自定义PersistenceManager类中初始化我的数据存储时:

lazy var persistentContainer: MergePolicedNSPersistentContainer = {

    let container = MergePolicedNSPersistentContainer(name: "MyAppDataModel")
    container.loadPersistentStores()
    { (storeDescription, error) in

        container.viewContext.mergePolicy = self.mergePolicy

        if let error = error as NSError?
        {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    }
    return container
}()