Realm (Swift):如何在迁移过程中获取 MutableSet 数据?

Realm (Swift): How to get at MutableSet data during migration?

我有一个本地 Realm(使用 RealmSwift API 版本 10.15.1),它有一个 Player 我正在尝试迁移的对象。 Player 当前包含名为 preferredPositions 的字段,它是一个 MutableSet<PositionClass>Player 的定义如下所示:

@objc final class Player: Object {
    @Persisted(primaryKey: true) var playerId: ObjectId
    @Persisted var name: String = ""
    @Persisted var preferredPositions: MutableSet<PositionClass> = MutableSet<PositionClass>()
    ...
}

PositionClass 看起来像这样:

class PositionClass: Object {
    @Persisted(primaryKey: true) var positionClassId: String = ""
    @Persisted var name: String = ""
    @Persisted var order: Int = 0
    @Persisted var abbreviation: String = ""
    ...
}

我想进行迁移,将 preferredPositionsMutableSet<PositionClass> 更改为 List<PositionClass>,因为现在我想订购 preferredPositions

所以新的 Player 看起来像:

@objc final class Player: Object {
    @Persisted(primaryKey: true) var playerId: ObjectId
    @Persisted var name: String = ""
    @Persisted var preferredPositions: List<PositionClass> = List<PositionClass>()
    ...
}

但是,我无法弄清楚迁移配置中访问 preferredPositions 数据的魔法咒语。

在我的迁移中我有:

    let schemaVersion: UInt64 = 22
    let config = Realm.Configuration(schemaVersion: schemaVersion,
                                    migrationBlock: { migration, oldSchemaVersion in
        ...
        if (oldSchemaVersion < 22) {
            migration.enumerateObjects(ofType: Player.className()) { oldObject, newObject in
                if let preferredPositionsSet: MutableSet<PositionClass> = oldObject!["preferredPositions"] as? MutableSet<PositionClass> {
                    let preferredPositionsList: List<PositionClass> = List()
                    preferredPositionsSet.forEach { (positionClass: PositionClass) in
                        preferredPositionsList.append(positionClass)
                    }
                    newObject!["preferredPositions"] = preferredPositionsList
                } else {
                    NSLog("preferredPositionsSet is nil.")
                }
            }
        }
    })
    Realm.Configuration.defaultConfiguration = config

但是线

let preferredPositionsSet: MutableSet<PositionClass> = oldObject!["preferredPositions"] as? MutableSet<PositionClass>

总是returns 零。我查看了调试器,似乎 oldObject!["preferredPositions"]MutableSet<PositionClass>。例如,如果我添加代码:

    let preferredPositionsAny = oldObject!["preferredPositions"]

然后在它显示的调试器中查看 preferredPositionsAny

所以,基础类型是正确的,但我不知道如何正确地理解它。

或者我应该以不同的方式进行迁移吗?

代码 TL;DR:

    let schemaVersion: UInt64 = 22
    let config = Realm.Configuration(schemaVersion: schemaVersion,
                                    migrationBlock: { migration, oldSchemaVersion in
        ...
        if (oldSchemaVersion < 22) {
            migration.enumerateObjects(ofType: Player.className()) { oldObject, newObject in
                let newRealm = newObject!.realm
                let preferredPositionsList: List<PositionClass> = List()
                let preferredPositionsSet = oldObject!.dynamicMutableSet("preferredPositions")
                preferredPositionsSet.forEach { positionClass in
                    if let newPositionClass = newRealm?.object(ofType: PositionClass.self, forPrimaryKey: positionClass["positionClassId"]) {
                        preferredPositionsList.append(newPositionClass)
                    }
                }
                newObject!["preferredPositions"] = preferredPositionsList
            }
        }

更完整的答案:

有几件事我弄错了:

  1. “旧”对象的数据类型不是 MutableSet<PositionClass>,而是 MutableSet<DynamicObject>。这就是为什么转换为 MutableSet<PositionClass> 总是 returning nil.
  2. 还有一种更清晰的方法来获取旧的 MutableSet,所以不用调用
let preferredPositionsSet = oldObject!["preferredPositions"] as! MutableSet<DynamicObject>

从我发现

let preferredPositionsSet = oldObject!.dynamicMutableSet("preferredPositions")

其中似乎有 return 相同的对象,但同样更清楚一点

  1. 从这个答案:,要用现有的 PositionClass 实例重新填充新的 List(而不是创建新实例),您需要从中获取数据境界。但是为了得到一个参数来获取数据。由于“旧”MutableSet 包含 DynamicObject,您需要使用命名字段的 DynamicObject 方法访问它,例如positionClass["positionClassId"] 而不是访问实际基础对象类型上的 属性,例如positionClass.positionClassId。这就是
let newRealm = newObject!.realm
if let newPositionClass = newRealm?.object(ofType: PositionClass.self, forPrimaryKey: positionClass["positionClassId"]) {
...

来自.