Swift - Coredata Migration - 根据旧属性值设置新属性值

时间:2016-11-17 06:06:18

标签: ios swift core-data

我当前的核心数据实体之一 - Entity1 - 具有名为Boolean的{​​{1}}属性。

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

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

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

2 个答案:

答案 0 :(得分:31)

轻量级迁移无法做到这一点。您必须创建映射模型和NSEntityMigrationPolicy的子类。对于大多数iOS开发人员而言,这并不困难,但这是一个陌生的领域。步骤如下:

  1. 创建映射模型。在Xcode中,文件 - >新 - >映射模型。当您单击“下一步”时,Xcode将询问此映射的源(旧)和目标(新)模型文件。
  2. 模型文件将尽可能推断映射。其他一切都是空白的。使用type和其他一些属性,它看起来如下所示。 $source.timestamp之类的条目意味着在迁移之前复制现有值。
  3. Initial mapping

    1. 创建NSEntityMigrationPolicy的新子类。给子类一个明显的名称,如ModelMigration1to2。该类将告诉Core Data如何将旧布尔值映射到新的整数值。

    2. 向子类添加方法以转换值。像下面这样的东西。方法名称并不重要,但如果您选择描述性的内容则很好。你需要在这里使用ObjC类型 - 例如NSNumber代替IntBool

      func typeFor(isSaved:NSNumber) -> NSNumber {
          if isSaved.boolValue {
              return NSNumber(integerLiteral: 1)
          } else {
              return NSNumber(integerLiteral: 2)
          }
      }
      
    3. 返回映射模型并告诉它使用您的子类作为其自定义映射策略。那是在“自定义政策”下右侧的检查员。请务必包含模块名称和类名。

    4. Custom Policy

      1. 告诉映射模型使用您之前创建的函数从旧type属性获取isSaved属性的值。以下说使用一个参数调用名为typeForIsSaved:的自定义策略类(:很重要)上的函数,并且该参数应该是isSaved上的$source值(旧的托管对象)。
      2. Custom attribute mapping

        迁移现在应该。您不必告诉Core Data使用映射模型 - 它会发现需要迁移并寻找与新旧模型版本匹配的模型。

        几点说明:

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

答案 1 :(得分:6)

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

例如,我的价值表达:

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

我的转化政策方法名称:

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

绝对棘手并且在模型更改后启动我的应用程序时触发它之前需要进行大量实验。它可能更容易实现" createDestinationInstances"对于你的政策,如果所有这些都不起作用,但我们会将其留下另一天......