'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 |