Realm (Swift):如何在迁移期间获取 MutableSet 数据?

Posted

技术标签:

【中文标题】Realm (Swift):如何在迁移期间获取 MutableSet 数据?【英文标题】:Realm (Swift): How to get at MutableSet data during migration? 【发布时间】:2021-11-30 17:47:13 【问题描述】:

我有一个本地 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&lt;PositionClass&gt; 更改为 List&lt;PositionClass&gt;,因为现在我希望订购 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>

总是返回零。我查看了调试器,似乎oldObject!["preferredPositions"]MutableSet&lt;PositionClass&gt;。例如,如果我添加代码:

    let preferredPositionsAny = oldObject!["preferredPositions"]

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

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

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

【问题讨论】:

没有什么真的让我觉得“错了”。如果你这样做let preferredPositionsAny = oldObject!["preferredPositions"] 然后print(preferredPositionsAny) 和/或迭代集合会发生什么。您要打印到控制台的数据吗?我正在尝试验证数据是否实际可用而不是 nil。 谢谢@Jay,它显示它是一个Realm.Swift.MutableSet&lt;RealmSwift.DynamicObject,然后底层是一个MutableSet&lt;PositionClass&gt;,所以是的,数据在那里。 【参考方案1】:

代码 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
            
        

更完整的答案:

有几件事我弄错了:

    “旧”对象的数据类型不是MutableSet&lt;PositionClass&gt;,而是MutableSet&lt;DynamicObject&gt;。这就是为什么MutableSet&lt;PositionClass&gt; 的演员总是返回nil。 还有一种更清晰的方法来获取旧的MutableSet,所以不要调用
let preferredPositionsSet = oldObject!["preferredPositions"] as! MutableSet<DynamicObject>

来自https://***.com/a/37588630/1204250我发现

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

这似乎有返回相同的对象,但同样,更清楚一点

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

来自。

【讨论】:

非常有趣的发现。当我尝试使用dynamicMutableSet 时,XCode 将该行标记为以下错误Value of type 'MigrationObject' (aka 'DynamicObject') has no member 'dynamicMutableSet'。您使用的是什么版本的 Realm,因为我在文档中根本找不到该参数。 嗯.. 我在 10.15.1。我可能会很快更新到最新版本。 @Jay 我刚刚更新到 10.17.0,它仍然对我有用。

以上是关于Realm (Swift):如何在迁移期间获取 MutableSet 数据?的主要内容,如果未能解决你的问题,请参考以下文章

在同一个项目中同时使用 Realm Swift 和 Realm Objective-C

Realm Swift 2.0:“不允许操作”- 仅在设备上

如何在 Realm swift 中过滤为当前日期创建的事件?

无法从Swift中的Realm对象Server获取数据

iOS 应用在导航期间迁移到 swift3 后崩溃

如何在 Swift 中将 JSON 写入 Realm