Swift Realm迁移创建了从旧类型到新类型的引用

时间:2019-07-02 12:08:08

标签: ios swift realm realm-migration

最初我有以下课程:

@objcMembers public class NormalObjectRealm: Object {

    // Shared
    dynamic public var id:                String?
    dynamic public var title:             String?
    dynamic public var subTitle:          String?
    dynamic public var imageInfo:         ImageInfoRealm?
    dynamic public var descriptionString: String?
    public var categories = List<String>()
    public var count    = RealmOptional<Int>()
    public var episodes = List<String>()


    public static let realmPrimaryKey: String = "id"

    public override class func primaryKey() -> String? {
        return NormalObjectRealm.realmPrimaryKey
    }
}

@objcMembers public class ImageInfoRealm: Object {

    dynamic public var id: String?
    dynamic public var url:    String?

    public static let realmPrimaryKey: String = "id"

    public override class func primaryKey() -> String? {
        return ImageInfoRealm.realmPrimaryKey
    }

}

但是现在NormalObjectRealm有点像这样被合并到新类中:

@objcMembers public class MediaObjectRealm: Object {

    // Shared
    dynamic public var id:                String?
    dynamic public var title:             String?
    dynamic public var subTitle:          String?
    dynamic public var imageInfo:         ImageInfoRealm?
    dynamic public var descriptionString: String?
    public var categories = List<String>()
    dynamic public var type: String?

    // NormalObjectRealm
    public var episodeCount    = RealmOptional<Int>()
    public var episodes = List<String>()

    // OtherObjectRealm
    dynamic public var urlOne:    String?
    dynamic public var urlTwo: String?
    dynamic public var urlThree:   String?
    public var isExplicit = RealmOptional<Bool>()

    public static let realmPrimaryKey: String = "id"

    public override class func primaryKey() -> String? {
        return MediaObjectRealm.realmPrimaryKey
    }
}

我目前正在尝试在此处为过渡编写迁移,其基本思想是将大多数字段从NormalObjectRealm转移到MediaObjectRealm

这是我目前的迁移块的样子

Realm.Configuration(schemaVersion: schemaVersion, migrationBlock: { migration, oldSchemaVersion in
            if oldSchemaVersion < temp {
                print("RealmMigration: Applying migration from \(oldSchemaVersion) to \(temp)")

                migration.enumerateObjects(ofType: "NormalObjectRealm") { oldObject, newObject in
                    guard let oldObject = oldObject else {
                        return
                    }
                    guard let id = oldObject["id"] as? String else {
                        return
                    }
                    guard let title = oldObject["title"] as? String else {
                        return
                    }

                    guard let subTitle = oldObject["subTitle"] as? String else {
                        return
                    }

                    guard let imgInfo = oldObject["imageInfo"] else {
                        return
                    }
                    guard let count = oldObject["count"] as? RealmOptional<Int>? else {
                        return
                    }

                    guard let descriptionString = oldObject["descriptionString"] as? String? else {
                        return
                    }

                    let item = migration.create("MediaObjectRealm")
                    item["id"] = id
                    item["title"] = title
                    item["subTitle"] = subTitle
                    item["descriptionString"] = descriptionString
                    item["type"] = "myType"
                    item["episodeCount"] = episodeCount // Doesn't work either...

                    migration.enumerateObjects(ofType: "ImageInfoRealm") { oldImg, newImg in
                        guard let oldImg = oldImg else {
                            return
                        }

                        let inf = oldObject.value(forKey: "imageInfo")
                        print(inf)
                        let t = migration.create("ImageInfoRealm", value: inf)
                        print("doing it")
                        //                      print(t)
                        item.setValue(t, forKey: "imageInfo")

                    }
                }
            }
    })

idtitlesubTitle等(String?Date?变量)设置良好,并显示在新创建的MediaObjectRealm内数据库条目。但是,类型为imageInfo的{​​{1}}并没有像这样直接设置:ImageInfoRealm(或item.setValue(oldObject.value(forKey: "imageInfo"), forKey: "imageInfo"))导致领域崩溃,并告诉我该对象来自另一个对象领域,我必须将其复制过来。

  

'对象已由另一个领域管理。使用创建代替   将其复制到此领域。

像上面的代码中那样创建它会导致根本没有item["imageInfo"] = oldObject.value(forKey: "imageInfo")类型的任何项,即失去所有数据(因为MediaObjectRealm也不再存在)。 我想念什么吗?我基本上想要从NormalObjectRealm获取链接/引用,并将其复制到新的NormalObjectRealm

1 个答案:

答案 0 :(得分:0)

经过长期测试并尝试了各种可能性,我设法迁移了数据。 这就是我要做的事情。

我以此为基础:

class RealmMigrationObject {
    let migration: () -> ()

    init(migration: @escaping () -> ()) {
        self.migration = migration
    }
}

以及从中派生的类。像这样:

class MigrationObjectToThree: RealmMigrationObject {

    init() {
        super.init(migration: MigrationObjectToThree.migration)
    }

    private static func migration() {
        print("Migration to three | migration")

        var imageInfos:   [ImageInfo]      = []

        let config = Realm.Configuration(schemaVersion: 3, migrationBlock: { migration, oldSchemaVersion in

            print("Migration to three | migrationBlock")
            print("RealmMigration: Applying migration from \(oldSchemaVersion) to 3")

            migration.deleteData(forType: "ExploreSectionObjectRealm")

            migration.enumerateObjects(ofType: "ImageInfoRealm") { oldInfo, newObject in
                guard let oldInfo = oldInfo else {
                    return
                }

                guard let id = oldInfo["id"] as? String,
                      let url = oldInfo["url"] as? String,
                      let url500 = oldInfo["url500"] as? String,
                      let url400 = oldInfo["url400"] as? String,
                      let url300 = oldInfo["url300"] as? String,
                      let url200 = oldInfo["url200"] as? String,
                      let url100 = oldInfo["url100"] as? String,
                      let colorString = oldInfo["color"] as? String,
                      let color = UIColor(hexString: colorString) else {
                    return
                }
                imageInfos.append(ImageInfo(id: id,
                                            url: url,
                                            url500: url500,
                                            url400: url400,
                                            url300: url300,
                                            url200: url200,
                                            url100: url100,
                                            color: color))
            }

        })


        Realm.Configuration.defaultConfiguration = config
        do {
            let realm = try Realm(configuration: config)
        print("Realm is located at: \(realm.configuration.fileURL?.description ?? "")")
            print(realm.configuration.fileURL?.description ?? "") // Printing here on purpose  as it's easier to copy
        } catch {
        print("Realm Error: \(error), trying to rebuild realm from scratch")

            let deleteMigrationConfig = Realm.Configuration(schemaVersion: RealmHelper.schemaVersion,
                                                            deleteRealmIfMigrationNeeded: true)
            do {
                _ = try Realm(configuration: deleteMigrationConfig)
            } catch {
                print("Failed to instantiate: \(error.localizedDescription)")
            }
        }

        RealmHelper.removeRealmFiles()
        Realm.Configuration.defaultConfiguration = Realm.Configuration(schemaVersion: 3)

        imageInfos.forEach({ $0.save() })
    }
}

从那以后,我只需执行给定对象的migration函数,就为所有架构上的当前架构版本和目标架构版本之间的差异创建了所有迁移。