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

时间:2017-12-20 21:07:53

标签: ios swift macos realm realm-migration

我在iOS项目中使用“常用”库。该库创建一个Realm数据库。到目前为止,我一直在iOS项目中使用这个库。我想现在使用与macOS项目相同的库。这是基于Foundation,并且不使用UIKit,为什么不呢?

问题在于:我有一个名为 Collection

的Realm类

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

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

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

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

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

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

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

 migration.enumerateObjects(ofType: "Collection", { (oldObject, _) in
    migration.create("SpecialCollection", value: oldObject)
 }

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

所以,我不能保留旧名称(Collection),我无法转换为新名称,我不能只是删除用户的数据。所以,我真的陷入了僵局。

块引用

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

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

感谢您的帮助。非常感谢。

1 个答案:

答案 0 :(得分:0)

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

所以我的表现如何:

  1. 首先迁移您的Collection类,创建SpecialCollection。
  2. 在迁移时,浏览Collection列表并创建新列表 每个ItemObject的SpecialItemObject并将其附加到新列表。
  3. 删除每个ItemObject。
  4. 现在枚举剩余的所有ItemObject 在领域中创建一个新的SpecialItemObject并映射其值 过度。原因是可能有其他ItemObject浮动 在你的领域,与列表无关。
  5. 删除所有剩余的ItemObject。
  6. 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") 
    

    所以这就是我昨晚在GitHub或SO或其他地方的可可领域中发现大部分内容之后,我自己为自己解决的问题。上面的示例仅与您提出的要求重命名ItemObject类的内容不同。您可以尝试创建新的ItemObject对象并以我在示例中显示的相同方式映射属性。我不明白为什么它不起作用。我已经提供了我的例子,我是如何解决自己的问题的,因为我昨晚测试了一些迁移以证明它是可靠的。

    由于你的问题差不多5个月了,我真的只是为后人发布这个答案。希望这有助于某人!

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