UIDocumentPickerViewController – Complete Guide

1 · Overview

UIDocumentPickerViewController (DPVC) is Apple’s drop‑in UI for letting users import, open, move, or export files in the system‑wide Files environment. It works on iOS, iPadOS and macOS (Catalyst) and interoperates automatically with third‑party File Provider extensions.

Think of it as a scoped portal into user‑selected files. Outside of the delegate callbacks you have no access to the user’s filesystem.

2 · Use Cases & Modes

2.1 Legacy Modes (UIDocumentPickerMode)

2.2 Modern Initializers (iOS 14+)

Apple deprecated the string‑based constructor and introduced UTType‑driven APIs:


import UniformTypeIdentifiers

// Import or open
let picker = UIDocumentPickerViewController(
    forOpeningContentTypes: [.pdf, .jpeg, .plainText],
    asCopy: false)

Companion initializers exist for forExporting and forOpeningContentTypes. The older init(documentTypes:in:) remains available but is deprecated on iOS 14+ .

3 · Initialising the Picker

3.1 Required Imports

Always import UniformTypeIdentifiers before referencing UTType symbols .

3.2 Constructor Matrix

TaskInitializerKey Parameters
Import / Open forOpeningContentTypes asCopy (Bool) → copy or open‑in‑place
Export forExporting asCopy (Bool) → move vs copy only
Legacy (pre iOS 14) init(documentTypes:in:) UIDocumentPickerMode

4 · Key Configuration Options

4.1 Allowed Types


let utTypes: [UTType] = [.pdf, .png, .jpeg, .plainText]
let picker   = UIDocumentPickerViewController(
                  forOpeningContentTypes: utTypes, asCopy: true)

4.2 Multiple Selection

Set allowsMultipleSelection = true on iOS 11+ to let users pick more than one file. For legacy code you must guard with if #available(iOS 11, *) .

4.3 Presentation Style

Use .formSheet or .pageSheet on iPad for a nicer Files‑style modal, or embed inside a navigation stack if you need continuous browsing.

5 · Delegate Workflow

5.1 Essential Callbacks


extension ViewController: UIDocumentPickerDelegate {

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

        // 1 ‑ start access for security‑scoped files
        for url in urls where url.startAccessingSecurityScopedResource() {
            defer { url.stopAccessingSecurityScopedResource() }
            // 2 ‑ process or copy the file
        }
    }

    func documentPickerWasCancelled(
        _ controller: UIDocumentPickerViewController) {
        // Dismiss UI / reset state
    }
}

Always wrap sandboxed URLs with startAccessingSecurityScopedResource /  stopAccessingSecurityScopedResource when asCopy is false; otherwise the file becomes unreadable outside the callback scope.

6 · Security‑Scoped Bookmarks & Persistence

If you need to keep long‑term access to an open‑in‑place file, turn the URL into a bookmark (bookmarkData), store it in Keychain / Core Data, then resolve via URL(resolvingBookmarkData:) when reopening the app. Never cache plain URLs – they go stale after a reboot.

7 · SwiftUI Integration

7.1 fileImporter


@State private var docs: [URL] = []
.fileImporter(isPresented: $showing,
              allowedContentTypes: [.item],
              allowsMultipleSelection: false) { result in
    docs = (try? result.get()) ?? []
}

7.2 fileExporter

For exporting (sharing) use fileExporter instead – it wraps the forExporting initializer under the hood.

8 · Edge Cases & Known Bugs (iOS 17.x)

Work‑arounds typically involve wrapping your dismiss logic in DispatchQueue.main.async to avoid presenting while de‑presenting.

9 · Complete Sample Controller


import UIKit
import UniformTypeIdentifiers

final class ImportViewController: UIViewController, UIDocumentPickerDelegate {

    @IBAction func chooseFile(_ sender: Any) {
        let picker = UIDocumentPickerViewController(
                        forOpeningContentTypes: [.pdf, .plainText], asCopy: true)
        picker.allowsMultipleSelection = false
        picker.delegate = self
        present(picker, animated: true)
    }

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

        guard let url = urls.first else { return }
        // Use url directly – already copied into sandbox
    }
}

10 · Best Practices

11 · Further Reading