Swift – Coredata迁移 – 根据旧的属性值设置新的属性值

我当前的核心数据实体之一 – Entity1 – 具有一个名为isSavedBoolean属性。

在新的核心数据模型中,我计划删除isSaved属性并添加一个名为type的新的Int属性。 对于所有保存的Entity1对象,我想根据旧核心数据模型中的isSaved值设置type的值。 (例如,如果isSaved为true,则type为1,否则type为2)。

我已经阅读了一些关于轻量级核心数据迁移的文章,但没有一篇似乎有帮助。

只是想知道是否有什么方法可以使我计划的迁移工作?

轻量级迁移不能做到这一点。 你将不得不创build一个映射模型和NSEntityMigrationPolicy的子类。 这并不困难,但对于大多数iOS开发人员来说这是陌生的领域。 步骤如下所示:

  1. 创build映射模型。 在Xcode中,文件 – >新build – >映射模型。 当你点击“下一步”时,Xcode会询问这个映射的源(旧)和目标(新)模型文件。
  2. 模型文件将尽可能地推断映射。 其他一切都将是空白的。 随着你的type和其他一些属性,它会看起来像下面这样。 像$source.timestamp这样的条目意味着复制迁移之前的现有值。

初始映射

  1. 创build一个NSEntityMigrationPolicy的新子类。 给这个子类一个明显的名字,比如ModelMigration1to2 。 这个类将告诉核心数据如何将旧的布尔值映射到新的整数值。

  2. 向子类添加一个方法来转换值。 像下面这样。 方法名称并不重要,但如果select描述性的内容,则很好。 你需要在这里使用ObjCtypes – 例如NSNumber而不是IntBool

     func typeFor(isSaved:NSNumber) -> NSNumber { if isSaved.boolValue { return NSNumber(integerLiteral: 1) } else { return NSNumber(integerLiteral: 2) } } 
  3. 回到映射模型,并告诉它使用你的子类作为它的自定义映射策略。 这是在“自定义策略”右侧的检查员。 确保包含模块名称和类名称。

自定义政策

  1. 通知映射模型使用您之前创build的函数从旧的isSaved属性获取type属性的值。 下面说调用一个名为typeForIsSaved:的自定义策略类上的一个函数typeForIsSaved: :是重要的)有一个参数,并且参数应该是$source (旧的被pipe理对象)上的isSaved值。

自定义属性映射

现在移民工作。 您不必告诉核心数据使用映射模型 – 它会发现需要迁移,并寻找一个匹配旧的和新的模型版本的模型。

几个注意事项:

  • 如果你崩溃的错误是类似的Couldn't create mapping policy for class named...那么你忘了上面的模块名称在步骤5(或错误的)。
  • 如果遇到unrecognized selector错误,则步骤4中的方法签名与您在步骤6中input的内容不匹配。

使用Xcode 9.1 Beta与Swift 4,我发现迁移的作品,但你必须小心如何指定变换方法的名称,也似乎你需要将你的函数标记为@objc。

例如,我的价值expression:

 FUNCTION($entityPolicy, "changeDataForData:" , $source.name) 

我的转换策略方法名称:

 class StudentTransformationPolicy: NSEntityMigrationPolicy { @objc func changeData(forData: Data) -> String { return String(data: forData, encoding: .utf8)! } } 

在模型更改之后启动我的应用程序之前,我需要进行大量的试验才能触发。 如果所有这些都不起作用,那么为您的策略实施“createDestinationInstances”可能会更容易,但是我们将在另一天离开这个…