LAST CHANCE: Save 50% on all my Swift books and bundles! >>

How to export files using fileExporter()

Paul Hudson    @twostraws   

Updated for Xcode 13.0

New in iOS 14

SwiftUI has a fileExporter() modifier that lets us export files from our app to anywhere the user wants – any folder in iCloud, or on their local device.

Using it takes several steps, because you must first have created a document type that your app is able to work with. I’m going to presume you’ve already done that so we can focus on fileExporter(), but if you haven’t already created a document type see the end of this article – I’ll provide an example there.

First, you need some state to track when you want the exporter UI to show or not. This is a simple Boolean, so you’d use something like this:

@State private var showingExporter = false

The next step is to add the fileExporter() modifier somewhere to your view hierarchy, passing in the Boolean state you just created, the document you want to export, and content type the document has.

Helpfully, the document parameter is optional, so you don’t need to have this set at all times. However, in order for the exporter UI to appear the document must be set and your state Boolean must have be true – you need both.

When the export operation completes, the file exporter will run a callback function of your choosing, passing in a Result object that either contains the URL where the file was saved or an error.

So, you would add this kind of modifier to your view hierarchy:

.fileExporter(isPresented: $showingExporter, document: yourDocument, contentType: .plainText) { result in
    switch result {
    case .success(let url):
        print("Saved to \(url)")
    case .failure(let error):
        print(error.localizedDescription)
    }
}

Note: I used .plainText for my content type, but that should match one of the content types you’ve set on your document type.

That’s all it takes to export a file, but just in case you’re missing this I want to provide an example document type that can be used here.

First, you’ll need to add a new import so that you can declare which content types your document can be used as:

import UniformTypeIdentifiers

And now you need to create some sort of type that conforms to the FileDocument protocol. This doesn’t take much, but you do need to tell SwiftUI how to load and save files, and also give it an initializer able to create new instances as needed.

Here’s an example, with comments to explain what it all does:

struct TextFile: FileDocument {
    // tell the system we support only plain text
    static var readableContentTypes = [UTType.plainText]

    // by default our document is empty
    var text = ""

    // a simple initializer that creates new, empty documents
    init(initialText: String = "") {
        text = initialText
    }

    // this initializer loads data that has been saved previously
    init(configuration: ReadConfiguration) throws {
        if let data = configuration.file.regularFileContents {
            text = String(decoding: data, as: UTF8.self)
        }
    }

    // this will be called when the system wants to write our data to disk
    func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
        let data = Data(text.utf8)
        return FileWrapper(regularFileWithContents: data)
    }
}

Click here to save 50% on all my books and bundles!

Similar solutions…

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.