领域 Swift 错误:无法直接创建嵌入式对象
Posted
技术标签:
【中文标题】领域 Swift 错误:无法直接创建嵌入式对象【英文标题】:Realm Swift Error: Embedded objects cannot be created directly 【发布时间】:2021-11-11 01:27:37 【问题描述】:我正在尝试将具有List<String>
类型属性的对象迁移到List<ChildObject>
类型,其中ChildObject
是自定义EmbeddedObject
。
示例
这就是我的意思:
import RealmSwift
final class ParentObject: Object
// Previously, this property was of type `List<String>`.
@Persisted public var children: List<ChildObject>
final class ChildObject: EmbeddedObject
@Persisted var name = ""
我正在使用此代码执行迁移,这会产生错误:
不能直接创建嵌入式对象
let configuration = Realm.Configuration(schemaVersion: 1) migration, oldSchemaVersion in
if oldSchemaVersion < 1
migration.enumerateObjects(ofType: ParentObject.className()) oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
let childrenObjects = newObject!["children"] as! List<MigrationObject>
// I'm trying to retain the previous values for `children` (of type `String`)
// where each value is used as the `name` property of a new `ChildObject`.
for string in childrenStrings
childrenObjects.append(
// This line produces the error :(
migration.create(ChildObject.className(), value: [string])
)
let realm = try! Realm(configuration: configuration)
问题
如何在保留先前值的同时执行迁移?
【问题讨论】:
既然你只是用旧对象的值添加一个新对象,为什么不像你一样迭代childrenStrings并在那个循环中创建新对象let c = ChildObject()
分配值@ 987654329@并将其添加到对象中?
嗨,杰。我遇到了几个类型不匹配的问题。在c.name = string
,我得到Cannot assign value of type 'DynamicObject'
(到String
)。正如 Rob 所说,我可以使用 String(describing:)
解决这个问题。但是,由于newObject!["children”]
和ChildObject
(c
) 之间的类型不匹配,您说“将其添加到对象”时我有点迷失了。
实际上,这似乎运作良好:newObject!["children"] = childrenStrings.map /* create new child object and assign name */ as [ChildObject]
。感谢您指出这一点。
酷。我认为这可能有效。您提到的那个错误是因为字符串转换为List<DynamicObject>
。请参阅我对this question 的回答,以快速获取列表中的项目并将其转换为字符串。
【参考方案1】:
最简单的做法是使用每个子对象的所有属性名称/值对创建一个Dictionary
,并使用这些对的数组创建一个完整的新List
。
但首先您需要从 children
的旧 List
中提取 String
值。这是必要的原因是因为 Realm 不会将 List<String>
的元素表示为实际的 String
(这是一个结构)。我们可以从description
字段中提取实际值:
childrenStrings
.map String(describing: $0)
一旦你有了名字,你就可以用Dictionary
来代表新的ChildObject
。请注意,您必须在 Dictionary
中包含所有属性名称和值。由于我们只有一个,称为“名称”,因此我们将其包括在内:
childrenStrings
.map String(describing: $0)
.map ["name": $0]
你的错误信息说:
不能直接创建嵌入式对象
但是,您可以使用Dictionary
中的Array
创建新对象,其中Array
对应于List
,每个Dictionary
对应一个ChildObject
对象。综上所述,我们有:
migration.enumerateObjects(ofType: ParentObject.className()) oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
newObject?.setValue(
Array(
childrenStrings
.map String(describing: $0)
.map ["name": $0]
),
forKey: "children"
)
【讨论】:
好的,谢谢!我可能会使用Array(childrenStrings.map [$0] )
之类的值来设置值以避免映射两次,但这很好。【参考方案2】:
分别总结 Rob 和 Jay 的解决方案:
选项 1
这是 Rob 修改后的解决方案。
migration.enumerateObjects(ofType: ParentObject.className()) oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
newObject!.setValue(
Array(childrenStrings.map [$0] ),
forKey: "children"
)
选项 2
这是基于 Jay 建议的解决方案。它创建的数组(或字典,如果使用命名参数)更少,并且应该使用更复杂的对象更好地扩展。
migration.enumerateObjects(ofType: ParentObject.className()) oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
newObject!["children"] = childrenStrings.map
let childObject = ChildObject()
childObject.name = "\($0)"
return childObject
as [ChildObject]
【讨论】:
以上是关于领域 Swift 错误:无法直接创建嵌入式对象的主要内容,如果未能解决你的问题,请参考以下文章