skip to Main Content

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

2

Answers


  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)
    
    Login or Signup to reply.
  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>
            }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search