Reputation: 320
I have a query regarding delegate method not been getting called for DocumentPickerViewController, here's the background, I just need to import the resource whatever available from my Files App and for that reason i am using UIDocumentPickerViewController.
I have a separate ViewController to which i add documentPickerViewController's view as subview and add it's delegate. My ViewController's code goes like this.
var documentPickerController: UIDocumentPickerViewController!
let supportedUTI = [kUTTypeImage,kUTTypeSpreadsheet,kUTTypePresentation,kUTTypeDatabase,kUTTypeFolder,kUTTypeZipArchive,kUTTypeVideo, kUTTypeAudiovisualContent]
documentPickerController = UIDocumentPickerViewController.init(documentTypes: supportedUTI as [String], in: .import)
documentPickerController.delegate = self
documentPickerController.allowsMultipleSelection = false
view.addSubview(documentPickerController.view)
Now as i see pickercontroller is opened and when i tap on Cancel documentPickerWasCancelled
is called but when i select a file documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]
is not called.
I tried to dip in further to my surprise what i see is instead of showing my ViewController to which i add picker's view as subview if i directly show pickerViewController like this
UIDocumentPickerViewController *dc = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:[self UTITypes] inMode:UIDocumentPickerModeImport];
dc.delegate = self;
[MainVC presentViewController:dc animated:YES completion:nil];
both the delegate method are called just fine. I don't understand why. Can someone please help me out here!! Thanks in advance!!
Upvotes: 10
Views: 5535
Reputation: 1
Right after this line: view.addSubview(documentPickerController.view)
let documentBrowserVC =
documentPickerViewController.children.compactMap {
$0 as? UIDocumentBrowserViewController
}.first documentBrowserVC?.delegate = self
So you can get selected file URLs by UIDocumentBrowserViewControllerDelegate's functions:
func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL])
Upvotes: 0
Reputation: 921
Using iOS 15 I was struck by the same problem, and guess what: although didPickdocumentsAtURL is not called, the deprecated didPickDocumentAtURL is called in this case. I'll use that for now as I need single selection only anyway.
Upvotes: 0
Reputation: 11
The reason is because the delegate is deallocated if you do not put it in a var outside the function.
If you are in a static environment, you can create a static var delegate: DocumentPickerDelegateClass for example; otherwise, in a UIViewController just create the var delegate: DocumentPickerDelegateClass
In every case, put the var on top, where cannot be deallocated. Be careful when you choose the "static" option, you must use it with care.
Upvotes: 1
Reputation: 356
So I had the exact same issue, the documentPickerWasCancelled
delegate method is called but the didPickDocumentsAt
would not get called.
Also of note, when I moved all of the delegation/presentation logic into my base view controller the UIPickerDelegate methods worked as expected. This let me know that there weren't any configuration type issues blocking functionality.
I'm not exactly sure what the problem is but it seems that if the document picker is presented on a complex view hierarchy something breaks.
What I ended up doing to work around this issue was creating a new window and presenting the document picker there:
func showDocumentPicker() {
let documentTypes = ["public.image", "com.adobe.pdf"]
let picker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import)
picker.delegate = self
picker.allowsMultipleSelection = true
picker.modalPresentationStyle = .formSheet
let window = UIWindow(frame: UIScreen.main.bounds)
let newWindowBaseVC = UIViewController()
newWindowBaseVC.view.backgroundColor = UIColor.clear
window.rootViewController = newWindowBaseVC
window.windowLevel = UIWindow.Level.alert
window.makeKeyAndVisible()
newWindowBaseVC.present(picker, animated: false, completion: nil)
}
Upvotes: 2
Reputation: 1339
The answer is simple: This is inherited from a UIViewController. If you just add the view of the viewController to your view, the delegate methods are not called. A ViewController has its own lifecycle. Please have a read here:https://developer.apple.com/documentation/uikit/uidocumentpickerviewcontroller
So, apologies for being some kind of wrong. For sure you can add a sub-viewController showing just its view. But: I think that shouldn't be the use-case. It is a full screen ViewController conforming to design guides from apple itself. That being said, you should present it with:
func addPicker() {
var documentPickerController: UIDocumentPickerViewController!
documentPickerController = UIDocumentPickerViewController(documentTypes: [String(kUTTypePDF)], in: .import)
documentPickerController.delegate = self
documentPickerController.allowsMultipleSelection = false
present(documentPickerController, animated: true, completion: nil)
}
There are some bugs filed where developer discovered that the view is being dismissed before the delegate is called. As far as I have seen, this behavior was introduced with ios11 and occured also when the viewController was presented. I can't really say if this is fixed or not nor if this behavior is related to show it as a subview. (I think it is somehow fixed as it works with a presented viewController)
Anyway, you should just present it as written above and you are good to go.
Upvotes: -1