如何制作保持不变的核心数据对象的副本

Posted

技术标签:

【中文标题】如何制作保持不变的核心数据对象的副本【英文标题】:How to make a copy of a Core Data object, that remains untouched 【发布时间】:2016-11-16 04:58:52 【问题描述】:

核心数据,自动更新导致问题的更改对象,并使事情变得比需要的更混乱。

假设我有这段代码:

let fetchRequest = Track.fetchRequest()

//update it
do 
    let tracksFound = try self.managedObjectContext.fetch(fetchRequest) as! [Track]
    print("retrieved")

    let trackToUpdate = tracksFound[0]

    trackToUpdate.locality = "please dont have updated"

    do 
        try self.managedObjectContext.save()
        print("saved")
    
    catch 
        fatalCoreDataError(error)
    

    for t in tracksFound 
        print(t.locality)
    

catch 
    fatalCoreDataError(error)

你可以看到它获取了一个[Track] 对象数组,然后它用please dont have updated 正确地更新了locality 的第一个元素。然后它保存这个对象。最后它会读取开头定义的tracksFound 数组。我原以为tracksFound 保持不变,对象tracksFound[0].locality 已更改为please dont have updated

如何阻止 Core Data 更新我的对象?我基本上想复制一份tracksFound 保持不变,这样我以后可以用它来做决策。

谢谢

【问题讨论】:

很简单,如果你没有调用 save() 方法意味着你的对象将保持不变。 代码let trackToUpdate = tracksFound[0] 获得对该元素的引用,而不是副本。因此,当您更改trackToUpdate 时,您实际上是在更改tracksFound[0] @Karthick 不,除此之外很危险。 【参考方案1】:

正如迈克尔的评论中提到的,trackToUpdate 是对NSManagedObject 实例的引用。指向同一个对象的不同引用,……指向同一个对象。所以没有办法改变一个对象而让另一个保持不变,因为没有其他对象。斯威夫特通过意图混淆了引用,无论谁有这个非常非常聪明的想法。

正如你所说,你必须创建一个副本。 NSManagedObject 没有实现 NSCopying 协议。这样做有充分的理由:如果实例引用其他实例(关系),您必须决定是否也复制它们。这样做会导致复制整个图表的危险。不这样做,会让您回到最初的问题,即您共享一个引用的实例。你必须做出决定。

最好将属性复制到一个简单的字典中。请记住,创建一个新实例,这将成为对象图的一部分。拥有“短时间”托管对象是一种代码味道(甚至这个词可能太难了)。

但是,您可以创建一个新实例。然后通过-entity 获取对象的实体描述。实体描述有一个属性-properties,它包含所有属性的列表。使用它,您可以遍历源属性并将其存储到新实例中。由于 Objective-C 的键值编码,可以在运行时执行此操作。

【讨论】:

感谢您的解释!

以上是关于如何制作保持不变的核心数据对象的副本的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 中核心数据对象的多个副本

核心数据迁移问题:“持久存储迁移失败,缺少源托管对象模型。”

不变模式

了解什么是不变模式

如何识别核心数据托管对象模型——哈希?

我应该如何存储核心数据“选定”项目?