SwiftUI导出报错:UIDocumentPickerViewController初始化仅支持Import/Open模式
解决方案
一、修复UIDocumentPickerViewController初始化错误
报错原因是UIDocumentPickerViewController(documentTypes:in:)仅支持.import和.open模式,你使用的.exportToService模式不兼容该初始化方法。要实现选择保存位置,需改用.open模式并开启目录选择权限:
修改DocumentPickerView的makeUIViewController方法:
func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPickerView>) -> UIDocumentPickerViewController { let documentTypes = [kUTTypeFolder as String, kUTTypeZipArchive as String] let exportPicker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .open) exportPicker.delegate = context.coordinator exportPicker.modalPresentationStyle = .formSheet // 允许用户选择保存目录 exportPicker.allowsDirectorySelection = true // iOS14+优化设置 if #available(iOS 14.0, *) { exportPicker.allowsMultipleSelection = false exportPicker.shouldShowFileExtensions = true } return exportPicker }
同时调整Coordinator的回调逻辑,在用户选择的目录下生成指定名称的zip文件:
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { guard let selectedDirURL = urls.first else { print("No directory selected for export") return } // 生成目标zip文件路径 let zipFileName = "exported_data.zip" let exportURL = selectedDirURL.appendingPathComponent(zipFileName) // 处理已存在的同名文件(示例直接删除,可改为提示用户) let fileManager = FileManager.default if fileManager.fileExists(atPath: exportURL.path) { try? fileManager.removeItem(at: exportURL) } completion(exportURL) }
二、修复导出函数逻辑错误
原导出函数存在逻辑冲突:先创建zip文件,再写入图片到同一目录,最后重新压缩会覆盖原有zip,导致最终文件仅包含单张图片。正确流程是先将所有待压缩文件存入临时目录,再一次性压缩:
修改后的exportDataAsZip方法:
func exportDataAsZip(to url: URL) { let fileManager = FileManager.default // 创建唯一临时目录存放待压缩文件 let tempDirURL = fileManager.temporaryDirectory.appendingPathComponent("ExportTemp_\(UUID().uuidString)") do { // 创建临时目录 try fileManager.createDirectory(at: tempDirURL, withIntermediateDirectories: true) // 1. 复制文档目录内容到临时目录 let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! try fileManager.copyItem(at: documentsDirectory, to: tempDirURL.appendingPathComponent("Documents")) // 2. 导出Core Data图片到临时目录的Images子文件夹 let imagesDirURL = tempDirURL.appendingPathComponent("Images") try fileManager.createDirectory(at: imagesDirURL, withIntermediateDirectories: true) let managedObjectContext = PersistenceController.shared.container.viewContext let fetchRequest: NSFetchRequest<CapturedImage> = CapturedImage.fetchRequest() let images = try managedObjectContext.fetch(fetchRequest) for image in images { guard let imageData = image.image, let timestamp = image.timestamp else { continue } let dateFormatter = ISO8601DateFormatter() let dateString = dateFormatter.string(from: timestamp) let imageUrl = imagesDirURL.appendingPathComponent("\(dateString).jpg") try imageData.write(to: imageUrl) } // 3. 压缩临时目录到目标zip文件 let success = SSZipArchive.createZipFile(atPath: url.path, withContentsOfDirectory: tempDirURL.path) success ? print("Exported data to: \(url.path)") : print("Failed to create ZIP archive") // 4. 清理临时目录 try fileManager.removeItem(at: tempDirURL) } catch { print("Export error: \(error.localizedDescription)") // 异常时清理临时目录 try? fileManager.removeItem(at: tempDirURL) } }
三、额外配置
- 导入必要框架:
import MobileCoreServices import SSZipArchive
- 在
Info.plist中添加文件访问权限描述:
<key>NSFileProviderDomainUsageDescription</key> <string>需要访问Files应用以保存导出的zip文件</string>
内容的提问来源于stack exchange,提问作者phiredrop
相关产品推荐
相关产品推荐

