如何让Realm与SwiftUI List(children:)实现层级列表展示?
问题:SwiftUI List层级展示Realm父子关系数据失败
尝试用Realm构建父子关系数据,并通过SwiftUI List的children:初始化器实现层级展示(带展开箭头)。已完成无父节点列表展示,但在适配children:参数时遇到类型转换问题。
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 } }
ContentView代码
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) } } }
尝试的扩展及错误
为适配children:参数,尝试扩展BlockList转换子节点类型,但报错:
extension BlockList { var childBlockListsArray: AnyRealmCollection<BlockList> { AnyRealmCollection(childBlockLists) } }
Key path value type 'AnyRealmCollection' cannot be converted to contextual type 'AnyRealmCollection?'
询问如何正确提供Realm数据及其子节点键路径以实现层级展示。
解决方案
1. 调整子节点属性的可选类型
SwiftUI List的children:参数要求子节点路径的类型是可选的集合类型(因为可能没有子节点),所以需要把扩展属性改为返回AnyRealmCollection<BlockList>?,空集合时返回nil:
extension BlockList { var children: AnyRealmCollection<BlockList>? { // 当子列表为空时返回nil,否则包装为AnyRealmCollection childBlockLists.isEmpty ? nil : AnyRealmCollection(childBlockLists) } }
2. 使用List的层级初始化器
修改ContentView中的List实现,使用List(children:)初始化器,传入父节点集合和子节点的键路径:
struct ContentView: View { @ObservedResults(BlockList.self) var blockLists var body: some View { let parentBlockLists = blockLists.where { $0.parentBlockList.count == 0 } // 使用children参数指定子节点键路径 List(parentBlockLists, children: \.children) { 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) } } }
关键说明
AnyRealmCollection是Realm提供的可观察集合类型,能和SwiftUI的ObservedResults配合实现自动更新- 必须返回可选类型(
?),因为当节点没有子元素时,List需要隐藏展开箭头 - 直接使用
\.children键路径即可,无需手动转换数组类型
内容的提问来源于stack exchange,提问作者DaPhil
相关产品推荐
相关产品推荐

