What is the difference between `FileDocument` and `ReferenceFileDocument` for `DocumentGroups` in SwiftUI?

1.9k Views Asked by At

I'm trying to setup a DocumentGroup in my app, but there's no examples out there yet ReferenceFileDocument is for. I know what a FileDocument is, but how are ReferenceFileDocuments different.

In the docs all it says is:

Conformance to ReferenceFileDocument is expected to be thread-safe, and deserialization and serialization will be done on a background thread.

2

There are 2 best solutions below

0
On BEST ANSWER

ReferenceFileDocument is a document type that will auto-save in the background. It is notified of changes via the UndoManager, so in order to use it you must also make your document undo-able.

The only mention I see of it in the docs is here.

Here is a working example.

0
On

There's a hint in the name: ReferenceFileDocument is a document that's a reference type (ie, a class). FileDocument is for a struct based document.

This has an effect on how documents are saved because SwiftUI can just make a copy of the reference type and save it without worrying about you coming along and modifying it during the save, since it's a value type or tree of value types.

With ReferenceFileDocument, there also doesn't seem to be a clear way for the SwiftUI to know when to save, so it depends on you telling it. There's no direct "doc is dirty, save it now" method, so the way you inform SwiftUI that you've done something that requires saving is through the undo manager.

You also need to provide a snapshot method to return a copy of the document that's safe for it to save.

final class QuizDocument: ReferenceFileDocument, ObservableObject {
    
    @Published var quiz: QuizTemplate

    init(quiz: QuizTemplate) {
        self.quiz = quiz
    }

    static var readableContentTypes: [UTType] { [.exampleText] }

    init(configuration: ReadConfiguration) throws {
        guard let data = configuration.file.regularFileContents,
              let quiz = try? JSONDecoder().decode(QuizTemplate.self, from: data)
        else {
            throw CocoaError(.fileReadCorruptFile)
        }

        self.quiz = quiz
    }

    // Produce a snapshot suitable for saving. Copy any nested references so they don't
    // change while the save is in progress.
    func snapshot(contentType: UTType) throws -> QuizTemplate {
        return self.quiz
    }

    // Save the snapshot
    func fileWrapper(snapshot: QuizTemplate, configuration: WriteConfiguration) throws -> FileWrapper {
        let data = try JSONEncoder().encode(quiz)
        return .init(regularFileWithContents: data)
    }
}