Core Data 在更新旧对象时创建一个新对象

Posted

技术标签:

【中文标题】Core Data 在更新旧对象时创建一个新对象【英文标题】:Core Data Creates A New Object When Updating An Old One 【发布时间】:2019-05-28 16:15:35 【问题描述】:

首先,我不相信这是重复的:Updating object value in core data is also creating a new object(它在 Obj-C 中,他们每次 segued 时都会调用 insertNewObject。)

背景信息:我从 Ray Wenderlich 的书中学习了如何使用 CoreData,并在编写此代码时参考了它。如果你有这本书,我会按照第 3 章中的概述推出我自己的自定义堆栈。如果需要,我可以显示此代码。

队列是我要更​​新的实体。

它有 1 个属性:名称 - 字符串

还有一对多的关系:任务:任务 我的 CoreData 逻辑位于包含 managedContext 的 Struct 中。

我有一个基本的查找/创建函数来创建队列对象。这行得通。它创建 1 个且仅 1 个对象。

func findOrCreateMainQueue() -> Queue? 
    let queue = Queue(context: managedContext)
    queue.name = "Queue32"

    let queueFetch: NSFetchRequest<Queue> = Queue.fetchRequest()
    queueFetch.predicate = NSPredicate(format: "%K == %@", #keyPath(Queue.name), "Queue32" as CVarArg)
    do 
        let results = try managedContext.fetch(queueFetch)
        print(results.count)

        if results.count > 0 
            return results.first!
         else 
            try managedContext.save()
        

     catch let error as NSError 
        print("Fetch error: \(error) description: \(error.userInfo)")
    

    return nil

(从 queue.name 后缀数字可以看出,我尝试了很多不同的方法。)

我已经尝试了所有我能想到的:

这段代码基本上是复制/粘贴自:How do you update a CoreData entry that has already been saved in Swift?

func addTaskToMainQueue2(task: Task) 
    let queueFetch: NSFetchRequest<Queue> = Queue.fetchRequest()
    queueFetch.predicate = NSPredicate(format: "%K == %@", #keyPath(Queue.name), "Queue32" as CVarArg)
    do 
        let results = try managedContext.fetch(queueFetch)
        print(results.count)

        if results.count > 0 

            var tasks = results[0].tasks?.mutableCopy() as? NSMutableOrderedSet
            tasks?.add(task)
            results[0].setValue(tasks, forKey: "tasks")
        

     catch let error as NSError 
        print("Fetch error: \(error) description: \(error.userInfo)")
    

        do 
            try managedContext.save()
         catch let error as NSError 
            print("Save error: \(error),description: \(error.localizedDescription)")
        



这会导致使用“Queue32”名称创建第二个 Queue 对象。

这是我尝试的另一件事:

func addTaskToMainQueue(task: Task) 
    if var queue = findOrCreateMainQueue() 
        var tasks = queue.tasks?.mutableCopy() as? NSMutableOrderedSet
        tasks?.add(task)
        queue.tasks = tasks
        do 
            try managedContext.save()
         catch let error as NSError 
            print("Save error: \(error),description: \(error.localizedDescription)")
        

    

为了篇幅,我不会为我尝试过的其他事情添加代码。

我尝试过使用查找/创建功能并在该方法中进行更新。 我尝试将队列保存为本地对象并将其传递给 addTask 函数,这也会导致重复。 我是传入Task还是在addTask函数中创建一个也没关系。

我开始相信我的问题出在我的 dataModel 文件中,因为我尝试了许多在线“如何更新核心数据对象”教程,但每次都得到相同的结果。

每当我尝试更新对象时,都会调用

awakeFromInsert()。不确定这是否应该发生。

在我的应用更新工作的其他地方。例如,如果我将子任务添加到任务。它工作正常。但是,如果我想更改另一个名为 Project 的实体的名称,则该对象会重复。 (项目有一个 id 属性被获取,然后 name 属性被改变。)

提前谢谢你。我已经把头发拉了好几个小时了。

【问题讨论】:

【参考方案1】:

我承认没有阅读您的所有代码,但如果您创建一个像这样的新托管对象

let queue = Queue(context: managedContext)

然后它将被添加到managedContext 并在某个时候保存到磁盘。所以这段代码

if results.count > 0 
    return results.first!
 else 
    try managedContext.save()

与之前创建的queue 对象无关,因为即使results.count > 0,它也会被保存,尽管稍后会保存。所以这意味着你必须在获取成功时删除queue,这感觉没有必要,最好等待创建它

if results.count > 0 
    return results.first!
 else 
    let queue = Queue(context: managedContext)
    queue.name = "Queue32"
    try managedContext.save()

题外话,但我看到如果创建了新对象而不是获取了新对象,则返回 nil,这是故意的吗?

【讨论】:

非常感谢。我假设当函数没有调用 save() 时删除了“队列”值。

以上是关于Core Data 在更新旧对象时创建一个新对象的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI + Core Data - 更新对象(Detail -> DetailEdit)

在 Core Data 中插入一个新的托管对象

Core Data,我如何有效地查找和删除托管对象

使用 XCode 8 中 Core Data 生成的类创建对象数组

防止 Core Data 创建空对象

Core-Data 后台保存性能问题