如何正确向SwiftData ModelDocument文件包添加数据文件
解决方案:正确在SwiftData ModelDocument包内存储大型二进制文件
你的问题核心是绕过了ModelDocument的文件管理机制直接写入磁盘,导致SwiftData在同步文档状态时,将未被跟踪的二进制文件识别为“冗余文件”并清理。以下是修正方案:
1. 正确获取ModelDocument实例
不要仅通过documentConfiguration拿URL,直接获取ModelDocument对象,它已经处理了沙箱权限和文件跟踪:
// 在MainWindowView中 @Environment(\.documentConfiguration) private var documentConfiguration private var modelDocument: ModelDocument<Entry> { documentConfiguration.document as! ModelDocument<Entry> }
2. 通过ModelDocument的FileWrapper管理附属文件
ModelDocument基于FileWrapper实现包结构,所有文档内的文件必须通过它的fileWrapper属性添加,这样SwiftData才会跟踪这些文件,不会在保存时删除:
func saveReferencedData(_ data: Data, modelDocument: ModelDocument<Entry>) throws { let logger = Logger(subsystem: "saveReferencedData", category: "Asset") let referencedFileName = "\(entryIdentifier)_\(assetIdentifier).\(assetType)" // 获取文档当前的FileWrapper var docFileWrapper = modelDocument.fileWrapper // 创建二进制数据对应的FileWrapper let assetFileWrapper = FileWrapper(regularFileWithContents: data) // 将新文件添加到文档包中 docFileWrapper.addFileWrapper(assetFileWrapper, withFilename: referencedFileName) do { // 更新文档的FileWrapper并触发保存 try modelDocument.update(fileWrapper: docFileWrapper) self.referencedFileLocation = referencedFileName logger.debug("成功保存二进制文件: \(referencedFileName)") } catch { logger.debug("保存失败: \(error.localizedDescription)") throw AssetFileOperationError.unableToSaveReferenceFile } }
3. 读取附属文件的正确方式
同样要通过ModelDocument的FileWrapper读取,避免直接操作磁盘:
func loadReferencedData(modelDocument: ModelDocument<Entry>) throws -> Data? { guard let fileName = referencedFileLocation else { return nil } let docFileWrapper = modelDocument.fileWrapper guard let assetWrapper = docFileWrapper.fileWrappers?[fileName], let data = assetWrapper.regularFileContents else { throw AssetFileOperationError.unableToLoadReferenceFile } return data }
关键注意事项
- 移除手动安全作用域调用:ModelDocument内部已经处理了沙箱的
startAccessingSecurityScopedResource(),手动调用会导致权限冲突或提前释放。 - 确认UTI配置:在Info.plist中确保你的自定义文档类型(
.myDocument)被标记为包类型(Bundle),这样系统才会允许文档包含多个文件。 - 禁止直接操作documentURL:所有文件操作必须通过ModelDocument的API进行,否则会破坏SwiftData的文档状态同步逻辑。
内容的提问来源于stack exchange,提问作者Cakelly
相关产品推荐
相关产品推荐

