Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 680
Joshua Olson Avatar asked Nov 20 '20 21:11

Joshua Olson


2 Answers

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)
    }
}
like image 73
stevex Avatar answered Sep 20 '22 01:09

stevex


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.

like image 43
Joshua Olson Avatar answered Sep 20 '22 01:09

Joshua Olson