SwiftUI文档类型协议FileDocument
SwiftUI文档类型协议FileDocument

SwiftUI文档类型协议FileDocument

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
   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注