Passing a FileDocumentReadConfiguration to a document struct's initializer in SwiftUI

Viewed 381

When you create a document-based SwiftUI project, the document struct contains the following initializer:

init(configuration: ReadConfiguration) throws {
    // Code to open an existing document
}

In the initial text editor project that Xcode supplies, you don't have to supply the configuration argument when calling the document's initializer in the App file.

var body: some Scene {
    DocumentGroup(newDocument: Document()) { file in
        ContentView(document: file.$document)
    }
}

In my project the document contains an array of another struct and saves the document in a file package. Now the compiler complains that I'm missing the configuration argument in the call to the document's initializer.

If I supply a FileDocumentReadConfiguration object as the configuration argument,

DocumentGroup(newDocument: Document(configuration: FileDocumentReadConfiguration())) { file in
    ContentView(document: file.$document)
}

The compiler provides the following error message:

FileDocumentReadConfiguration cannot be constructed because it has no accessible initializers

The information on FileDocumentReadConfiguration in Apple's documentation has nothing on initializers. Searching for FileDocumentReadConfiguration on Google yields only Apple's documentation and an unanswered question on the Hacking with Swift forums. No one has asked a question about this on Stack Overflow.

How do I supply a FileDocumentReadConfiguration object to the document's initializer or how can I avoid having to supply a configuration argument like the default project does?

2 Answers

The implementation details of the SwiftUI structs FileDocumentReadConfiguration, ReferenceFileDocumentConfiguration, etc. are not documented simply because they are not public. In order to be platform independent, SwiftUI takes care of a lot of default behaviours which can be confusing because by doing so it also hides a lot of information. In order to avoid the ReadConfiguration conundrum we need to do like the Xcode template and provide a custom initializer either with a default value there or in the variable declaration. That is the initialization that you call in the DocumentGroup init and let SwiftUI take care of the details.

var body: some Scene {
    DocumentGroup(newDocument: Document()) { file in
        ContentView(document: file.$document)
    }
}

This is a place where a new document is created, i.e. there is no file representation yet.

If you declare your Document as FileDocument you need to provide initializer with ReadConfiguration, which in this case is typealias to FileDocumentReadConfiguration and this initializer will be called by system when your application is asked to open existed document of corresponding document type:

struct Document: FileDocument {

    // here configuration is-a `FileDocumentReadConfiguration`
    init(configuration: ReadConfiguration) throws {
        // read here your content from configuration using `configuration.file` 
    }

   // ... other code
}
Related