在 Realm swift 中重命名类的最佳方法

Dan*_*row 5 macos realm ios swift realm-migration

我在我的 iOS 项目中使用了一个“通用”库。这个库创建了一个 Realm 数据库。到目前为止,我只在 iOS 项目中使用过这个库。我现在想在 macOS 项目中使用相同的库。它是Foundation基于的,不使用UIKit,为什么不呢?

问题是:我有一个名为的 Realm 类 Collection

Collection 也是标准 Swift 协议的名称。

虽然我已经能够在我的 iOS 项目上摆脱这个名称冲突,但出于某种原因,我不能在我的 MacOS 项目上做同样的事情——它创建了一个名称集合。

我读到了这个可以像这样使用的符号:

@objc(SpecialCollection)
class Collection: Realm.Object {
   let items: List<ItemObject>
   let name: String
   let url: String
  ....
}
Run Code Online (Sandbox Code Playgroud)

因此,这解决了名称冲突问题。在 ObjC 中,名称会有所不同,但在 Swift 中,我不需要更改任何内容。

除了我本地的 Realm 数据库之外,这一切都很好。我有很多Collection应该重命名的对象SpecialCollection(因为 Realm 在 Swift 下使用 ObjC)。我想执行迁移来执行此操作,但显然还没有支持的方法来执行此操作?我注意到 github 上关于这个问题的票被“监视”了,但不幸的是,仍然没有已发布的解决方案来解决这个问题。

我的所有Collection对象都包含List对象(因此得名)。因此,我尝试对Collection迁移中的所有对象运行枚举......我只需要旧对象,并使用新名称创建一个新对象,如下所示:

 migration.enumerateObjects(ofType: "Collection", { (oldObject, _) in
    migration.create("SpecialCollection", value: oldObject)
 }
Run Code Online (Sandbox Code Playgroud)

但是由于oldObject有其他对象的列表,Realm 的迁移将尝试创建任何List对象中的所有项目......这是无法完成的,因为它创建了具有相同primaryKey值的对象(导致崩溃)。

所以,我不能让旧名称(集合),我不能转换为新的名称,我不能只垃圾桶用户的数据。所以,我真的陷入了僵局。

块引用

我尝试oldObject在创建新对象之前进行修改,但您无法oldObject在迁移中进行更改。

唯一的规则是旧数据必须保留,我不能在这里破坏用户的领域。

感谢您在这方面的任何帮助。不胜感激。

Sma*_*cat 4

昨晚我遇到了非常相似的问题。我有几个想要重命名的 Realm 类,其中一个类有一个引用第二个类的 List 属性。因此,与您的问题相比,唯一的区别是我也重命名了 ItemObject 类。

所以我是这样做的:

  1. 首先迁移您的 Collection 类,创建 SpecialCollection。
  2. 迁移时,遍历 Collection 的列表并为每个 ItemObject 创建新的 SpecialItemObject 并将其附加到新列表中。
  3. 删除每个 ItemObject。
  4. 现在枚举领域中剩余的所有 ItemObject 并创建一个新的 SpecialItemObject 并映射其值。原因是可能有其他 ItemObject 漂浮在您的领域中,但未绑定到列表。
  5. 删除所有剩余的 ItemObject。

migration.enumerateObjects(ofType: "Collection")
{ (oldObject, newObject) in
    let specialCollection = migration.create(SpecialCollection.className())
    specialCollection["name"] = oldObject!["name"]
    specialCollection["url"] = oldObject!["url"]

    if let oldItems = oldObject!["items"] as? List<MigrationObject>,
       let newItems = specialCollection["items"] as? List<MigrationObject>
    {
        for oldItem in oldItems
        {
            let newItem = migration.create(SpecialItemObject.className())
            newItem["name"] = oldItem["name"]  // You didn't specify what was in your ItemObject so this example just assumes a name property.
            newItems.append(newItem)
            migration.delete(oldItem)
        }
    }
}
migration.deleteData(forType: "Collection")

// Now migrate any remaining ItemObject objects that were not part of a Collection.
migration.enumerateObjects(ofType: "ItemObject")
{ (oldObject, newObject) in
    let newItem = migration.create(SpecialItemObject.className())
    newItem["name"] = oldItem["name"]
}

// Now let's be sure we'll have no further ItemObject in our entire Realm.
migration.deleteData(forType: "ItemObject") 
Run Code Online (Sandbox Code Playgroud)

这就是我昨晚自己解决这个问题的方法,在 GitHub、SO 或其他地方的 cocoa-realm 中几乎找不到任何关于此问题的信息。上面的示例与您所要求的唯一不同之处在于您没有要求重命名 ItemObject 类。您可以尝试创建新的 ItemObject 对象并按照我在示例中显示的相同方式映射属性。我不明白为什么它不起作用。我已经提供了我的示例,准确说明了我如何解决自己的问题,因为我昨晚测试了一些迁移以证明它是可靠的。

由于你的问题已经近 5 个月了,我只是为了后代发布这个答案。希望这对某人有帮助!

在 iOS 11.3 sim / Xcode 9.3 / Swift 4.1 上使用 Realm 3.3.2 进行测试