'iOS Document Picker crashes when picking a PDF on a real device

I try to create a Document Picker for my iOS app.

Here is my code (I wrapped the UIDocumentPickerViewController in my SwiftUI View, with UIViewControllerRepresentable):

import SwiftUI
import MobileCoreServices

struct DocumentPickerViewController: UIViewControllerRepresentable {
    var callback: (Data) -> ()

    func makeCoordinator() -> Coordinator {
        return Coordinator(documentController: self)
    }

    func updateUIViewController(
        _ uiViewController: UIDocumentPickerViewController,
        context: UIViewControllerRepresentableContext<DocumentPickerViewController>) {
    }

    func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
        let controller = UIDocumentPickerViewController(documentTypes: [String(kUTTypePDF)], in: .open)
        controller.delegate = context.coordinator
        return controller
    }

    class Coordinator: NSObject, UIDocumentPickerDelegate {
        var documentController: DocumentPickerViewController

        init(documentController: DocumentPickerViewController) {
            self.documentController = documentController
        }

        func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
            guard let url = urls.first else { return }

            let fileManager = FileManager.default
            print(fileManager.fileExists(atPath: url.path))
            let data = NSData(contentsOfFile: url.path)
            let file = UploadFileData(fileName: "\(url)", fileType: .file, fileData: data!)
            let dataFile = file.fileData as Data
            
            documentController.callback(dataFile)
        }
    }
}

enum UploadFileType{
    case photo
    case file
}

struct UploadFileData {
    var fileName: String
    var fileType: UploadFileType
    var fileData: NSData
}

var file: UploadFileData?

It works on my Simulator, but when I pick a PDF on a real device, I get the following error: Fatal error: Unexpectedly found nil while unwrapping an Optional value: file MyApp/DocumentPickerViewController.swift, line 44

ie for line: let dataFile = file.fileData as Data



Solution 1:[1]

The issue there is that you are using the wrong mode when defining the type of file transfer operation used by the document picker. .open is used to open an external file located outside your app’s sandbox. What you need is to use .import it will create a temporary file that will allow you to load its contents or move/copy the file to a permanent location. If it doesn't solve you issue check this post on how to implement your DocumentPickerViewController coordinator

let controller = UIDocumentPickerViewController(documentTypes: [String(kUTTypePDF)], in: .import)

Solution 2:[2]

If you are using UIDocumentPickerViewController via UIViewControllerRepresentable then use initializer with asCopy parameter

let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.pdf], asCopy: true)

if ios target above ios 14 then use .fileImporter presentation modifier

.fileImporter(isPresented: $showDocumentPicker,
                      allowedContentTypes: [.pdf],
                      allowsMultipleSelection: true)
        { result in
            // processing results Result<[URL], Error>
        }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Leo Dabus
Solution 2 Sergei Volkov