SwiftUI中基于选中文件夹获取CoreData文件时@FetchRequest编译报错
解决SwiftUI中@FetchRequest无法访问EnvironmentObject的编译错误
错误原因
你遇到的编译错误是因为属性初始化器在self完全初始化前就会执行,而@EnvironmentObject修饰的appState属于视图实例的成员,在@FetchRequest初始化时还无法访问self.appState,因此直接在@FetchRequest的predicate中引用appState.selectedFolder会导致编译失败。
解决方案
我们可以通过两种方式实现动态过滤文件的需求:
方案一:在视图内部监听选中文件夹变化,动态更新FetchRequest
通过手动创建FetchRequest实例,监听appState.selectedFolder的变化来动态修改查询条件:
struct FileListView: View { @EnvironmentObject var appState: AppState // 手动声明FetchRequest和对应的结果集 private var fileFetchRequest: FetchRequest<File> private var files: FetchedResults<File> { fileFetchRequest.wrappedValue } init() { // 初始查询条件:显示所有文件 let initialPredicate = NSPredicate(value: true) fileFetchRequest = FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \File.order, ascending: true)], predicate: initialPredicate, animation: .default ) } var body: some View { List { ForEach(files) { file in Text(file.name) } } .onReceive(appState.$selectedFolder) { selectedFolder in // 根据选中的文件夹更新查询条件 let targetPredicate: NSPredicate if let folder = selectedFolder { targetPredicate = NSPredicate(format: "folder = %@", folder) } else { targetPredicate = NSPredicate(value: true) } // 更新FetchRequest的查询条件,自动刷新结果 fileFetchRequest.nsPredicate = targetPredicate } } }
方案二:将查询条件作为参数传入视图
把FileListView设计为接收NSPredicate参数的通用视图,由父视图根据appState的状态生成对应的查询条件:
// 通用文件列表视图 struct FileListView: View { @FetchRequest var fileList: FetchedResults<File> // 初始化时传入查询条件 init(predicate: NSPredicate) { _fileList = FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \File.order, ascending: true)], predicate: predicate, animation: .default ) } var body: some View { List { ForEach(fileList) { file in Text(file.name) } } } } // 父视图中使用 struct MainView: View { @EnvironmentObject var appState: AppState var body: some View { // 根据选中文件夹生成对应的查询条件 let filePredicate = appState.selectedFolder.map { NSPredicate(format: "folder = %@", $0) } ?? NSPredicate(value: true) FileListView(predicate: filePredicate) .environmentObject(appState) } }
两种方案都能实现需求:当选中文件夹时显示该文件夹下的文件,未选中时显示所有文件。方案一更适合把过滤逻辑封装在FileListView内部,方案二则更灵活,便于复用视图。
内容的提问来源于stack exchange,提问作者StuckOverFlow
相关产品推荐
相关产品推荐

