我试图使用Realm作为具有父/子关系的数据库,并使用children:
初始化器在分层SwiftUI列表中显示数据。我在SwiftUI+Realm教程中找到了自己。我的Realm类看起来像这样:
import Foundation
import RealmSwift
class BlockList: RealmSwift.Object, RealmSwift.ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var id: RealmSwift.ObjectId
@Persisted var title: String
@Persisted var childBlockLists = RealmSwift.List<BlockList>()
@Persisted(originProperty: "childBlockLists") var parentBlockList: RealmSwift.LinkingObjects<BlockList>
convenience init(title: String) {
self.init()
self.title = title
}
}
然后我的内容视图看起来像这样:
struct ContentView: View {
@ObservedResults(BlockList.self) var blockLists
var body: some View {
let parentBlockLists = blockLists.where {
($0.parentBlockList.count == 0)
}
List(parentBlockLists) { blockList in
Text(blockList.title)
}
.toolbar {
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}
func addItem() {
let realm = try! Realm()
let newBlockList = BlockList(title: "New List")
let newSubBlockList = BlockList(title: "New SubList")
newBlockList.childBlockLists.append(newSubBlockList)
try! realm.write {
realm.add(newBlockList)
}
}
}
显示所有没有父节点的列表。下一步将是使用List(children:)
分层显示数据,即显示那些具有带雪佛龙的子列表以扩展列表的列表。
为此,children参数需要子节点的关键路径。但是,我不知道如何提供。我试着写一个扩展到BlockList,并提供一个函数,将孩子转换成有用的东西,但我的方法都不起作用:
extension BlockList {
var childBlockListsArray: AnyRealmCollection<BlockList> {
AnyRealmCollection(childBlockLists)
// guard let set = childBlockLists as? Array<BlockList>, set.isEmpty == false else { return nil }
// childBlockLists.count == 0 ? nil : AnyRealmCollection(childBlockLists)
// childBlockLists.count == 0 ? nil : Array(childBlockLists)
}
}
我觉得我在AnyRealmCollection
中最接近铸造,然后使用
List(AnyRealmCollection(parentBlockLists), children: .childBlockListsArray)
但是我仍然得到错误
密钥路径值类型'AnyRealmCollection'不能为转换为上下文类型'AnyRealmCollection?'
我如何提供正确的Realm
数据和它们的子键路径显示在SwiftUIsList
?
让我试着回答,因为我认为你需要的一切都已经存在于你的问题中,而不需要任何额外的代码。
我相信我们的目标是生成一个父母列表,然后在UI中生成一个v形或披露三角形,供用户单击,然后显示他们的孩子-所有这些都是用一个模型完成的。
这是你的(简化)模型
class BlockList: RealmSwift.Object {
@Persisted var title: String
@Persisted var childBlockLists = RealmSwift.List<BlockList>()
@Persisted(originProperty: "childBlockLists") var parentBlockList: RealmSwift.LinkingObjects<BlockList>
convenience init(title: String) {
self.init()
self.title = title
}
}
现在用一些数据填充域来测试;父母和孩子。在这个例子中,ParentA有两个孩子,而ParentB和ParentC有一个孩子。
let parentA = BlockList(title: "parent A")
let parentB = BlockList(title: "parent B")
let parentC = BlockList(title: "parent C")
let child0ofParentA = BlockList(title: "child 0 of Parent A")
let child1ofParentA = BlockList(title: "child 1 of Parent A")
let child0ofParentB = BlockList(title: "child 0 of Parent B")
let child0ofParentC = BlockList(title: "child 0 of Parent C")
parentA.childBlockLists.append(child0ofParentA)
parentA.childBlockLists.append(child1ofParentA)
parentB.childBlockLists.append(child0ofParentB)
parentC.childBlockLists.append(child0ofParentC)
try! realm.write {
realm.add([parentA, parentB, parentC])
}
最后,让我们读入数据并显示一个列表——类似于在UI
中所做的操作//get all of the parents
let parents = realm.objects(BlockList.self).where { $0.childBlockLists.count > 0 }
parents.forEach { parent in
print("parent title: (parent.title)")
parent.childBlockLists.forEach { child in
print(" child title: (child.title)")
}
}
和输出——这与用户点击每个父
的披露三角形相同parent title: parent A
child title: child 0 of Parent A
child title: child 1 of Parent A
parent title: parent B
child title: child 0 of Parent B
parent title: parent C
child title: child 0 of Parent C
请注意,我根本没有使用parentBlockList
,所以它可以在这个用例中被删除。也许你想把图从子节点横移回父节点?
SwiftUI部分只是像显示父对象一样显示子对象,你似乎已经知道如何显示对象列表。
就用数组吧。
extension BlockList {
// Map the children to an array.
// Note: SwiftUI.List expects this variable to be optional
var children: [BlockList]? { self.childBlockLists.map { $0 } }
}
struct ContentView: View {
@ObservedResults(BlockList.self) var blockLists
// Perform your filtering in a computed variable. Avoid performing calculations in the view's body
var parentBlockLists: [BlockList] {
blockLists
.where { $0.parentBlockList.count == 0 } // Filter results
.map { $0 } // Map to array
}
var body: some View {
List(parentBlockLists, children: .children) { blockList in
Text(blockList.title)
}
.toolbar {
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}