核心数据实体唯一约束不起作用

use*_*617 4 constraints core-data ios swift

我正在尝试使用新的实体约束检查器在核心数据中设置约束(以使项目的名称唯一)。我读过的所有内容都表明这非常简单 - 设置约束并处理错误。我没有收到任何错误,并且可以根据需要多次添加相同的条目。

该应用程序确实需要 IOS 9.0,Xcode 工具要求设置为 7.0

约束category1Name 是一个字符串。

我的 addItem 代码是:

func addNewRecord() {

    //check to be sure the entry is not empty
    if (categoryTextField.text == "") {

        //prompt requiring a name
        let ac = UIAlertController(title: nil, message: "Name Required", preferredStyle: .Alert)
        ac.addAction(UIAlertAction(title: "Ok", style: .Default, handler: nil))
        self.presentViewController(ac, animated: true, completion: nil)

    } else {

    let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName("Category1", inManagedObjectContext: kAppDelegate.managedObjectContext) as! Category1

    newManagedObject.category1Name = categoryTextField.text
    newManagedObject.category1Description = categoryTextView.text

    //bunch more items...

    //save it
    kAppDelegate.saveContext()
    makeEntryFieldsEnabledNO()
    performSegueWithIdentifier("unwindToCategoriesTableViewController", sender: self)

    }//if  else

}//addNewRecord
Run Code Online (Sandbox Code Playgroud)

AppDelegate 保存是标准的:

func saveContext () {
    if managedObjectContext.hasChanges {
        do {
            try managedObjectContext.save()
        } catch {

            //insert your standard error alert stuff here
            let nserror = error as NSError
            print("From the print line: Unresolved error \(nserror), \(nserror.userInfo)")

            abort()
        }//do catch
    }//if moc
}//saveContext
Run Code Online (Sandbox Code Playgroud)

这是核心数据约束:

在此输入图像描述

此应用程序已启用 iCloud。

ManagedObjectContext 合并策略设置为 NSMergeByPropertyObjectTrumpMergePolicy

lazy var managedObjectContext: NSManagedObjectContext = {
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
    let coordinator = self.persistentStoreCoordinator
    var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator
    managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    return managedObjectContext

}()//var managedObjectContext
Run Code Online (Sandbox Code Playgroud)

任何指导将不胜感激。

Fat*_*tie 5

Apple 似乎终于解决了 Xcode 的疯狂问题,即您在数据模型文件中所做的更改实际上并没有改变。

\n

抛开这一点,当前的公式似乎是:

\n

在你的核心数据单例中......

\n
    container = NSPersistentContainer(name: _nom)\n    \n    // during development, right HERE likely delete the sql database file\n    // and start fresh, as described here stackoverflow.com/a/60040554/294884\n    \n    container.loadPersistentStores { storeDescription, error in\n        if let error = error {\n            print("\\n ERROR LOADING STORES! \\(error) \\n")\n        }\n        else {\n            print("\\n  STORES LOADED! \\(storeDescription) \\n")\n        }\n    \n        self.container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy\n        self.container.viewContext.automaticallyMergesChangesFromParent = true\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

您必须使用合并策略自动合并。

\n

然后在你的数据模型文件中

\n
    \n
  1. 除非每个关系都有逆关系,否则不要打扰
  2. \n
  3. 正确设置“一个或多个”
  4. \n
  5. 并且(几乎可以肯定,除了非常不寻常的源数据)每个实体的唯一 ID 被指示为约束
  6. \n
\n

然后当你添加新数据时,你必须

\n
    \n
  1. 使用由方便的核心数据函数提供的新背景上下文,它可以做到这一点
  2. \n
  3. 所以,永远不要尝试创建自己的单独线程
  4. \n
  5. 仔细检查您是否已完成 (1) 和 (2)!
  6. \n
  7. 当您添加一些实体时,您必须perform
  8. \n
  9. 当您完成添加实体(即在新线程上)时,您必须仍在执行...
  10. \n
  11. 做一个 PerformAndWait 做两件事
  12. \n
  13. 保存新项目(在新的线程上),然后
  14. \n
  15. 保存新项目(在主视图线程上)
  16. \n
  17. 当然,对于 7 和 8,您必须在保存之前检查 .hasChanges
  18. \n
\n

容易吧?

\n

所以像

\n
let pm = core.container.newBackgroundContext()\npm.perform {\n    for onePerson in someNewData {\n        ... create your new CDPerson entity ...\n    }\n    pm.bake()\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,烘焙例程位于执行块内,

\n

它看起来像这样:

\n
func bake() {\n    self.performAndWait {\n        if self.hasChanges {\n            do {\n                try self.save()\n            }\n            catch {\n                print("bake disaster type 1 \\(error)")\n            }\n        }\n        \n        // OPTIONALLY, SEE BELOW\n        if core.container.viewContext.hasChanges {\n            do {\n                try core.container.viewContext.save()\n            }\n            catch {\n                print("bake disaster type 2 \\(error)")\n            }\n        }\n        // OPTIONALLY, SEE BELOW\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

需要明确的是,请注意pm.bake函数中的 ... bake()self前半部分中的 确实是newBackgroundContext为执行中的循环创建的。

\n

请注意,现在您甚至不需要保存到主上下文

\n

automaticallyMergesChangesFromParent如果你“完成上面长列表中的所有事情”,现在似乎工作得很好。

\n

\xe2\x80\xa2 在上面的烘焙中,添加几行打印行以查看保存到 viewContext 的内容。你会发现什么都没有被保存。这一切都是由子/引擎中的任何关系正确完成的

\n

\xe2\x80\xa2 所以事实上,你可以省略这段代码。你所要做的就是

\n
func bake() {\n    self.performAndWait {\n        if self.hasChanges {\n            do {\n                try self.save()\n            }\n            catch {\n                print("bake disaster type 1 \\(error)")\n            }\n        }\n}\n
Run Code Online (Sandbox Code Playgroud)\n