How to let user select file from Files

Quick look at the `UIDocumentPickerViewController` to access the Files app.

Published: May 6, 2022
I want a Press Kit

iOS lets us - apart from importing media from the Photos library - also import either iCloud or local files from the Files app. In this post, we will look at how to accomplish that.

Selecting files

We will use UIDocumentPickerViewController (Apple docs) which handles all the hard work for us. This view controller presents the Files app interface, and we get back callback with the result.

Since iOS 14 we can use UTType to specify which files we are interested in. In this example we want JPG and PNG images. So we create the picker like this:

let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.jpeg, .png])
documentPicker.delegate = self
documentPicker.modalPresentationStyle = .overFullScreen

I use the .overFullScreen to give the picker maximum available space. Want multiple selection? There is simple property for it:

documentPicker.allowsMultipleSelection = true

And lastly, we can show it:

present(documentPicker, animated: true)

And that is the first part done.

How to pick file from Files? UIDocumentPickerViewController example

Here is the entire code to open UIDocumentPickerViewController:

func openDocumentPicker() {
    let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.jpeg, .png])
    documentPicker.delegate = self
    documentPicker.modalPresentationStyle = .overFullScreen

    present(documentPicker, animated: true)
}

Handling the delegate

When the user selects a file or files (assuming you allowed multi-select), we need to respond to the delegate of the document picker.

Specifically to this method for single selection:

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
    dismiss(animated: true)
}

And this one for multi selection:

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {

}

I will be using the single selection for simplicity. The multi one works the same; you just have to handle all the URLs.

There is also a method that gets called when the user closes the picker without making any selection. Should you need to handle it in your code:

func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {

}

Working with selected files

Once you have the URLs of the selected files from the delegate, there is one last thing to handle.

These URLs are security-scoped, so we need to do a bit of preparation before we access the contents.

To be more precise, we need to call startAccessingSecurityScopedResource() on the file URL. This returns a bool value indicating whether you can access the file or not.

I believe this should always be true, assuming you won’t try to modify the URL and access a different file/path than the one provided by the delegate.

I would recommend to copy the file to temporary directory once you get access to it. This of course depends on what you need to do with the file.

So very basic workflow could look something like this:

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
    dismiss(animated: true)

    guard url.startAccessingSecurityScopedResource() else {
        return
    }

    defer {
        url.stopAccessingSecurityScopedResource()
    }

    // Copy the file with FileManager
}

I am using defer to make sure stopAccessingSecurityScopedResource gets called once the rest of the code finishes.

Bluesky logo

Follow on Bluesky to not miss new posts

Filip Němeček profile photo

WRITTEN BY

Filip Němeček Mastodon

iOS blogger and developer with interest in Python/Django.

iOS blogger and developer with interest in Python/Django.