You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确向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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 13:55:04