FileDocument 是 SwiftUI 框架中用于构建“文档类型应用”的核心协议。它取代了 macOS 的 NSDocument 和 iOS 的 UIDocument,提供一个跨平台的、结构化的文件读取和写入机制。
定义
protocol FileDocument {
static var readableContentTypes: [UTType] { get }
init(configuration: ReadConfiguration) throws
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper
}
基本功能
1、读取文件:从磁盘打开用户选定的文件。
2、写入文件:保存用户修改后的内容。
3、指定文件类型:限制只处理某些类型(如 .txt, .json, .png)。
4、与 DocumentGroup 结合:实现“文档结构” SwiftUI App 的核心文档处理。
基本用法
1、定义文档类型
import SwiftUI
import UniformTypeIdentifiers
struct MyTextDocument: FileDocument {
static var readableContentTypes: [UTType] { [.plainText] }
var text: String = ""
init() {}
// 读取文件
init(configuration: ReadConfiguration) throws {
if let data = configuration.file.regularFileContents {
text = String(decoding: data, as: UTF8.self)
} else {
throw CocoaError(.fileReadCorruptFile)
}
}
// 保存文件
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
let data = Data(text.utf8)
return .init(regularFileWithContents: data)
}
}
FileDocument是SwiftUI的协议,用于声明一个文档类型的结构,实现它可以让SwiftUI打开文件和保存文件。
2、结合DocumentGroup使用
@main
struct MyDocumentApp: App {
var body: some Scene {
DocumentGroup(newDocument: MyTextDocument()) { file in
ContentView(document: file.$document)
}
}
}
DocumentGroup(…) 用于创建“文档结构”的App,newDocument:MyDocument() 表示创建新文档时,用这个类型初始化。
{ file in … } 定义每次打开一个文件时,用哪个View来展示,将文档内容作为 @Binding 传入主视图,支持实时更新。
3、ContentView视图
struct ContentView: View {
@Binding var document: MyTextDocument
var body: some View {
TextEditor(text: $document.text)
.padding()
}
}

FileDocument协议详解
import SwiftUI
import UniformTypeIdentifiers
struct MyTextDocument: FileDocument {
static var readableContentTypes: [UTType] { [.plainText] }
var text: String = ""
init() {}
// 读取文件
init(configuration: ReadConfiguration) throws {
if let data = configuration.file.regularFileContents {
text = String(decoding: data, as: UTF8.self)
} else {
throw CocoaError(.fileReadCorruptFile)
}
}
// 保存文件
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
let data = Data(text.utf8)
return .init(regularFileWithContents: data)
}
}
1)导入UniformTypeIdentifiers,引入UTType类型,如 .plainText, .image 等。
import UniformTypeIdentifiers
2)实现FileDocument协议:
struct MyDocument: FileDocument
3)支持的文档类型:
static var readableContentTypes: [UTType] { [.plainText] }
表示只打开 .txt(纯文本)类型。
4)文档保存的实际内容:
var text: String = ""
这里文档的内容由文本字符串保存。
5)文档初始化:
init()
新建文档时调用,默认内容为空。
6)打开已有文档时:
init(configuration: ReadConfiguration)
打开已有文档时调用,读取磁盘上的数据。
7)保存文档时调用:
fileWrapper(configuration:)
保存文档时调用,把txt写入一个FileWrapper(文件包)。
核心读取流程(打开文件时发生)
if let data = configuration.file.regularFileContents {
text = String(decoding: data, as: UTF8.self)
}
configuration.file.regularFileContents 是一个 Data?,代表文件内容。
将其解码为 UTF-8 字符串,赋值给 text。
核心写入流程(保存文件时发生)
let data = Data(text.utf8)
return .init(regularFileWithContents: data)
把 text 字符串编码为 Data。
创建一个新的 FileWrapper 对象(FileWrapper可见扩展知识部分)作为要写入的文件内容。
支持类型
通过 UniformTypeIdentifiers.UTType 指定支持的格式:
static var readableContentTypes: [UTType] {
[.plainText, .json, .png, .image]
}
也可以定义自定义类型(UTI)。
高级用法
1、支持多种文件类型。
2、保存/加载 JSON、图像、音频、富文本等格式。
3、使用 FileWrapper(directoryWithFileWrappers:) 支持多文件保存(项目型文档)。
4、使用 .fileExtensionVisibility(.visible) 控制文件扩展名显示。
5、结合 QuickLook 做预览界面。
总结
FileDocument 是 SwiftUI 的文档模型协议,可以实现打开/保存文档的功能。
通过配合DocumentGroup使用,适配iOS 14+,macOS 11+版本。
使用场景有:编辑器、阅读器、Markdown工具、图像处理器等。
相关文章
SwiftUI文档类型DocumentGroup:https://fangjunyu.com/2025/07/05/swiftui%e6%96%87%e6%a1%a3%e7%b1%bb%e5%9e%8bdocumentgroup/
2、macOS构建文档的NSDocument:https://fangjunyu.com/2025/07/03/macos%e6%9e%84%e5%bb%ba%e6%96%87%e6%a1%a3%e7%9a%84nsdocument/
3、macOS文档控制器NSDocumentController:https://fangjunyu.com/2025/07/03/macos%e6%96%87%e6%a1%a3%e6%8e%a7%e5%88%b6%e5%99%a8nsdocumentcontroller/
扩展知识
FileWrapper是什么?
FileWrapper 是 macOS 和 SwiftUI 中用来描述文件内容、文件夹或符号链接的对象。它广泛用于 FileDocument 的读写中,特别是在 fileWrapper(configuration:) 中,它是保存文件的标准返回类型。
可以把 FileWrapper 理解为一个「虚拟文件」,它代表即将写入磁盘的内容,可以是:
一个普通文件(如 .txt, .png, .json)。
一个目录(文件夹 + 子文件)。
一个符号链接(不常用)。
主要用途(SwiftUI)
在 FileDocument 中,SwiftUI 要求提供一个 FileWrapper,表示用户当前文档要保存的内容:
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
let data = Data(text.utf8)
return .init(regularFileWithContents: data)
}
这表示要保存一个「普通文件」,内容是 Data。
FileWrapper 的三种模式
1、普通文件
初始化方法FileWrapper(regularFileWithContents:),用于文本、图片、音频等,最常用。
let data = Data("Hello".utf8)
let wrapper = FileWrapper(regularFileWithContents: data)
这就是最常见的 .txt 或 .json 的保存形式。
2、目录文件夹
初始化方法FileWrapper(directoryWithFileWrappers:),用于项目、图集、文档包,可嵌套子文件。
let child1 = FileWrapper(regularFileWithContents: Data("A".utf8))
let child2 = FileWrapper(regularFileWithContents: Data("B".utf8))
let directory = FileWrapper(directoryWithFileWrappers: [
"a.txt": child1,
"b.txt": child2
])
这个结构表示一个“文件夹”,里面有两个文件 a.txt 和 b.txt。
3、符号链接
let wrapper = FileWrapper(symbolicLinkWithDestination: "target.txt")
初始化方法FileWrapper(symbolicLinkWithDestination:),UNIX 链接,很少使用。
读取时的FileWrapper
当用户打开文档时,SwiftUI 会把文件转换成 ReadConfiguration,里面包含一个 FileWrapper:
init(configuration: ReadConfiguration) throws {
if let data = configuration.file.regularFileContents {
text = String(decoding: data, as: UTF8.self)
}
}
configuration.file 是 FileWrapper。
regularFileContents 是读取文件本体的 Data。
如果支持文档包,还可以这样:
let wrapper = configuration.file
let children = wrapper.fileWrappers // [String: FileWrapper]
let textData = children["a.txt"]?.regularFileContents