MOCloner 是一个小型库,旨在实现 NSManagedObject 的可定制深度拷贝。支持一对一、一对多、多对多关系。除了忠实于原始数据的拷贝方法外,它还提供了诸如选择性拷贝和在拷贝过程中生成新值等功能。
通过 NSAttributeDescription、NSRelationshipDescription 遍历 NSMangedObject 的属性和关系,并通过 userinfo 设置深度拷贝参数。
更多实现细节,请参考 如何在 Core Data 中对 NSManagedObject 进行深拷贝。
拷贝一对一和一对多关系下的所有数据。
当遇到反向关系为 to-many 的 Entity 时,停止该 Entity 下分支的复制,并将新复制的对象添加到该 Entity 中。
创建上图中的 Note 的深度拷贝
let cloneNote = try! MOCloner().clone(object: note) as! Note
从关系链的中间部分向下进行深度拷贝(不拷贝关系链的向上部分)
// Add the exclude relationship names to the excludedRelationshipNames
let cloneItem = try! MOCloner().clone(object: item, excludedRelationshipNames: ["note"]) as! Item
MOCloner 通过在 Xcode 的 Data Model Editor 中向 User Info 添加键来定制深度拷贝过程。目前支持以下命令:
exclude
此键可以在 Attribute 或 Relationship 中设置。只要出现 exclude 键,无论任何值,都将启用排除逻辑。
在 Attribute 的 userinfo 中设置时,深度拷贝将不会拷贝原始对象属性的值(Attribute 必须是 Optional,或者已设置默认值)。
在 Relationship 的 userinfo 中设置时,深度拷贝将忽略此关系分支下的所有关系和数据。
为了方便某些不适合在 userinfo 中设置的情况(例如从关系链的中间进行深度拷贝),您还可以将需要排除的关系的名称添加到 excludedRelationshipNames 参数中(例如基本演示 2)。
rebuild
用于在深度拷贝期间动态生成新数据。目前支持两个值:uuid 和 now。
uuid:UUID 类型的 Attribute,在深度拷贝时为该属性创建一个新的 UUID
now:Date 类型的 Attribute,在深度拷贝时为该属性创建一个新的当前日期 (Date.now)
followParent
Derived 的简化版本,仅用于设置 Attribute,可以指定关系链下级 Entity 的 Attribute 获取关系链上级对应的 managed object 实例的指定 Attribute 的值(要求两个 Attribute 的类型相同)。在下图中,Item 的 noteID 将获得 Note 的 id 值。
withoutParent
仅与 followParent 一起使用。处理设置了 followParent 但从关系链中间进行深度拷贝时无法获取 ParentObject 的情况。
当 withoutParent 为 keep 时,将保留复制对象的原始值
当 withoutParent 为空时,将不为其设置值(Attribute 必须是 Optional 或设置了默认值)
如果以上 userinfo 键名与您的项目中已使用的键名冲突,您可以通过自定义 MOClonerUserInfoKeyConfig 重置它。
let moConfig = MOCloner.MOClonerUserInfoKeyConfig(
rebuild: "newRebuild", // new Key Name
followParent: "followParent",
withoutParent: "withoutParent",
exclude: "exclude"
)
let cloneNote = try cloner.cloneNSMangedObject(note,config: moConfig) as! Note
MOCloner 的最低要求是 macOS 10.13、iOS 11、tvOS 11、watchOS 4 及以上版本。
MOCloner 使用 Swift Package Manager 进行分发。要在另一个 Swift 包中使用它,请将其作为依赖项添加到您的 Package.swift 中。
let package = Package(
...
dependencies: [
.package(url: "https://github.com/fatbobman/MOCloner.git", from: "0.1.0")
],
...
)
如果想在您的应用程序中使用 MOCloner,请使用 Xcode 的 File > Add Packages... 将其添加到您的项目中。
import MOCloner
由于 MOCloner 只有几百行代码,您可以将代码复制到您的项目中并直接使用。
当深度拷贝涉及大量数据时,请在私有上下文中操作,以避免占用主线程。
最好在深度拷贝操作前后使用 NSManagedObjectID 进行数据传输。
当托管对象的深度拷贝涉及大量关系数据时,可能会导致大量内存使用。当它包含二进制数据(例如在 SQLite 中存储大量图像数据)时,这一点尤其明显。您可以考虑以下方法来控制内存使用:
在深度拷贝期间,暂时排除内存使用量高的属性或关系。深度拷贝完成后,通过其他代码逐一添加它们。
当深度拷贝多个 NSManagedObject 时,考虑通过 performBackgroundTask 逐一执行它们。
MOCloner 使用 MIT 许可,您可以自由地在您的项目中使用它。但请注意,MOCloner 不提供任何官方支持渠道。
Core Data 提供了丰富的功能和选项,开发者可以使用它们来创建大量的不同关系图组合。MOCloner 仅针对其中一些情况进行了测试。因此,在开始准备将 MOCloner 用于您的项目之前,强烈建议您花一些时间熟悉其实现,并进行更多的单元测试,以防您遇到任何可能的数据错误问题。
如果您发现问题、错误,或想提出改进建议,请创建 Issues 或 Pull Request。