SwiftUI fileExporter does not present when used as a button modifier within a toolbar modifier of DocumentGroup

Viewed 309

I'm having trouble getting the .fileExporter to present in SwiftUI under a specific scenario in iOS: when used as a button modifier in the toolbar of a DocumentGroup Scene.

See code below that shows the issue.

Expected result: When user presses "Save File" button, the .fileExporter should present and the user is prompted to save the file.

Actual results: Nothing appears to happen even though the state variable is changed and document is not nil.

Issue appears in the iOS 15.0 simulator, and iOS 15.1 and 15.2 using hardware. This does not appear in macOS 12.0.

Has anyone else had this issue? Is there a known workaround?


import SwiftUI

@main
struct myApp: App {
    
    @State private var showingFileExporter = false

    var body: some Scene {
        DocumentGroup(newDocument: myDocument()) { file in
            ContentView(document: file.$document)
                .toolbar {
                    Button("Save File") {
                        showingFileExporter = true
                    }
                    .fileExporter(isPresented: $showingFileExporter,
                                  document: file.document,
                                  contentType: UTType.exampleText) { result in
                        }
                }
        }
    }
}


import UniformTypeIdentifiers

extension UTType {
    static var exampleText: UTType {
        UTType(importedAs: "com.example.plain-text")
    }
}

struct myDocument: FileDocument {
    var text: String

    init(text: String = "Hello, world!") {
        self.text = text
    }

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

    init(configuration: ReadConfiguration) throws {
        guard let data = configuration.file.regularFileContents,
              let string = String(data: data, encoding: .utf8)
        else {
            throw CocoaError(.fileReadCorruptFile)
        }
        text = string
    }
    
    func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
        let data = text.data(using: .utf8)!
        return .init(regularFileWithContents: data)
    }
}


struct ContentView: View {
    @Binding var document: myDocument
    var body: some View {
        TextEditor(text: $document.text)
    }
}


1 Answers

I just had the same issue with my fileImporter and it does work if you move it our of .toolbar context

Here's my code:

 .toolbar {
            Button("Import") {
                presentImporter.toggle()
            }
    }
    .fileImporter(isPresented: $presentImporter, allowedContentTypes: [.mp3]) { result in
        switch result {
        case .success(let url):
            print(url)
            
            let newBook = Book(context: viewContext)
            newBook.name = "\(url.lastPathComponent)"
            newBook.url = url
            newBook.origin = playlist.self
            
            try? viewContext.save()
            let _ = print("New book", newBook.name as Any)
            let _ = print("inside", newBook.origin as Any)
            
        case .failure(let error):
            print(error)
        }
    }
Related