SwiftUI中List嵌套ForEach无法显示数据问题求助
问题:SwiftUI中List内的ForEach无法展示Core Data数据,VStack中却可以
我开发了一个SwiftUI视图,通过FetchRequest从Core Data获取数据并存储在navigations变量中。尝试在List组件内用ForEach遍历展示navigations内容,这种写法在其他视图里多次成功,但这里就是不显示数据。把完全一样的遍历代码放到VStack里却能正常展示。我肯定漏了某个简单细节,但一直找不到。
相关代码
import SwiftUI struct ContentView: View { @Environment(\.managedObjectContext) private var viewContext @FetchRequest( sortDescriptors: [SortDescriptor(\.date)], predicate: NSPredicate(value: false), animation: .default) private var navigations:FetchedResults<NavEntry> var event: Event var body: some View { ScrollView{ let _ = updatePredicate() VStack { Text("ForEach inside a VStack:") VStack(alignment: .leading) { ForEach(navigations) {nav in Text("\(longTime(date: nav.date)) \(nav.note)") } } Text("\n ForEach inside a List:") List { ForEach(navigations) {nav in Text("\(longTime(date: nav.date)) \(nav.note)") } } } } } func updatePredicate() { navigations.nsPredicate = NSPredicate(format: "event == %@", event) } }
输出截图

解决方法
问题出在你直接在body里调用updatePredicate()修改FetchRequest谓词的方式,这种写法会导致视图更新时机不匹配,List对数据源变更的感知逻辑和VStack不同,无法正确响应FetchedResults的更新。
推荐的正确写法是把FetchRequest改成动态计算属性,依赖传入的event参数,这样能自动响应event变化并更新数据源:
修改后的代码
import SwiftUI struct ContentView: View { @Environment(\.managedObjectContext) private var viewContext var event: Event // 基于event创建动态FetchRequest private var navigations: FetchRequest<NavEntry> { FetchRequest( sortDescriptors: [SortDescriptor(\.date)], predicate: NSPredicate(format: "event == %@", event), animation: .default ) } // 获取FetchedResults结果 private var navigationResults: FetchedResults<NavEntry> { navigations.wrappedValue } var body: some View { ScrollView{ VStack { Text("ForEach inside a VStack:") VStack(alignment: .leading) { ForEach(navigationResults) { nav in Text("\(longTime(date: nav.date)) \(nav.note)") } } Text("\n ForEach inside a List:") List { ForEach(navigationResults) { nav in Text("\(longTime(date: nav.date)) \(nav.note)") } } } } } func longTime(date: Date) -> String { // 补充日期格式化逻辑示例 let formatter = DateFormatter() formatter.dateStyle = .long formatter.timeStyle = .long return formatter.string(from: date) } }
原因说明
- 原来的写法中,在
body渲染时才修改谓词,List无法在正确的时机感知到数据源的变化,而VStack的渲染逻辑相对宽松,能显示出数据。 - 改成计算属性的
FetchRequest后,当event参数变化时,FetchRequest会自动重建,对应的FetchedResults也会同步更新,List和VStack都能正确展示数据。
备选方案
如果一定要保留原有的@FetchRequest写法,可以把updatePredicate()移到onAppear中调用,但这种方式仅在视图首次出现时生效,当event参数变化时不会自动更新:
var body: some View { ScrollView{ VStack { // ... 原有内容不变 } .onAppear { updatePredicate() } } }
内容的提问来源于stack exchange,提问作者Peel
相关产品推荐
相关产品推荐

