简体   繁体   中英

UIDocumentPickerDelegate method(didPickDocumentsAt) not called by iOS

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

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)
    }

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM