SwiftUI使用fileExporter导出文件时展示ProgressView的问题求解
解决方案
核心问题
原代码存在两处逻辑错误导致需求无法实现:
- 耗时的文档生成逻辑放在
FileDocument的初始化方法中,且直接在fileExporter参数中初始化FileDocument实例,这部分逻辑会在主线程执行,直接阻塞UI导致ProgressView无法正常渲染动画 - 用同一个状态
isExporting同时控制ProgressView显示和导出弹窗弹出,不符合「先生成文档、再弹出保存弹窗」的时序要求
完整实现代码
import SwiftUI import UniformTypeIdentifiers struct ContentView: View { // 控制加载动画显示 @State private var isGeneratingDocument = false // 控制导出弹窗显示 @State private var isExporting = false // 存储预生成的文档对象 @State private var generatedDocument: FileExport? var body: some View { ZStack { VStack { Button(action: { startGenerateDocument() }, label: { Text("Export File") }) .padding() } // 生成文档时展示全屏加载动画 if isGeneratingDocument { ProgressView("正在生成文档...") .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.ultraThinMaterial) } } // 导出修饰符挂载到根视图,文档生成完成后才触发弹窗 .fileExporter(isPresented: $isExporting, document: generatedDocument, contentType: .plainText) { result in defer { generatedDocument = nil } if case .success(let url) = result { print(url) print("File Saved") } else { print("File Not Saved") } } } private func startGenerateDocument() { // 先显示加载动画 isGeneratingDocument = true // 异步执行耗时操作,不阻塞主线程 Task { // 模拟2秒耗时的文档生成逻辑,替换为实际的大文件生成代码 try? await Task.sleep(nanoseconds: 2 * 1_000_000_000) // 生成文档对象 let document = FileExport(contents: "This is a simple Text") // 回到主线程更新UI await MainActor.run { // 隐藏加载动画 isGeneratingDocument = false // 存储生成好的文档 generatedDocument = document // 弹出导出选择弹窗 isExporting = true } } } } // FileDocument实现,仅做数据封装,无耗时逻辑 struct FileExport: FileDocument { static var readableContentTypes: [UTType] {[.plainText]} var contents: String init(contents: String) { self.contents = contents } init(configuration: ReadConfiguration) throws { guard let data = configuration.file.regularFileContents, let string = String(data: data, encoding: .utf8) else { throw CocoaError(.fileReadCorruptFile) } contents = string } func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { guard let data = contents.data(using: .utf8) else { throw CocoaError(.fileWriteUnknown) } return FileWrapper(regularFileWithContents: data) } }
关键改动说明
- 拆分了两个状态变量,严格区分「文档生成中」和「准备导出」两个阶段的UI展示逻辑,避免状态冲突
- 耗时的文档生成逻辑放到异步任务中执行,不阻塞主线程,保证
ProgressView可以正常渲染加载动画 - 预先生成完整的
FileDocument实例后再触发fileExporter弹窗,不会出现弹窗卡顿的问题
内容的提问来源于stack exchange,提问作者RXP
相关产品推荐
相关产品推荐

