问题
I have a WKWebView
in a view controller. When an user clicks on "Upload File" button (which is on the webpage shown), UIDocumentPickerViewController
pops up. This is expected and totally neccessary but:
Whenever the user clicks on any button ("Upload Photo or Video", "Cancel"), the UIDocumentPickerViewController
dismisses itself AND the parent view controller that it's in.
I have added a symbolic breakpoint for [UIViewController dismissViewControllerAnimated:completion:]
and indeed saw that -dismissViewController...
is called twice. After the first time it dismisses UIDocumentPickerViewController
, after the second one – my parent view controller.
By the way, on the iPad there is no problem, probably because UIDocumentPickerViewController
is presented as a popover.
Why is this happening and what should I do?
Thanks!
回答1:
Alright, I think I've found a way to fix this. WebKit is open source, and you can see the offending class is WKFileUploadPanel
, specifically the _dismissDisplayAnimated: method is called too aggressively inadvertently triggering dismissal of your view controller. In order to avoid this you need to block calls to -dismissViewControllerAnimated:completion:
that come in from WKFileUploadPanel
, which you can do by looking up the stack. Here's an implementation that resolves this.
The solution mentioned above doesn't work because it relies on looking at the call stack symbols for a particular class which is obfuscated when running on a real device. Here's a different approach I took to resolve this:
- Add a
weak
UIDocumentMenuViewController
property to your modal view controller class. - Override
-presentViewController:animated:completion:
in your modal class to check and see if the view controller being presented is aUIDocumentMenuViewController
, if so set it as the value for your weak property from step 1. - Override
-dismissViewControllerAnimated:completion:
to check if your weak property isnil
yet, if it is notnil
and your modal'spresentedViewController
isnil
then it means that WebKit is trying to dismiss your modal when it shouldn't be. You can avoid callingsuper
in that case, and continue calling it otherwise.
You can also swizzle WKFileUploadPanel
's _dismissDisplayAnimated: method to be more careful about your own view controllers, but that comes with a significant amount of risk.
回答2:
I faced the same problem and finally managed to find a workaround.
In my view controller I override dismiss
method to delete managed object if save button wasn't hit and that worked perfectly with UIImagePickerController
.
As of my application uses UIDocumentPickerViewController
, my managed object was deleted each time the documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL)
was called because this causes a presentingViewController.dismiss
.
So my solution is to check from the presentingViewController
if the presentedViewController
is nil
or not to know if dismiss
method was called by UIDocumentPickerViewController
or not.
So here is my overriden dismiss
method from my view controller.
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
if self.presentedViewController == nil {
// dismissed by the user
myDocument.delete()
} else {
// dismissed by the UIDocumentPickerViewController
// do nothing
}
super.dismiss(animated: flag, completion: completion)
}
Hope it helps you.
回答3:
I have faced the same issue , This happens while using document picker and occurs in iOS versions below 11.4 . Use the below code where ever you are using document picker. From what I have read from different forums there is an issue with document picker and it has been fixed in later versions of iOS .
Declare a weak property of document picker .
@property (weak, nonatomic) UIDocumentPickerViewController *_Nullable docPicker;
Then implement the view controller delegate methods :
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion
{
if ([viewControllerToPresent isKindOfClass:[UIDocumentPickerViewController class]])
{
_docPicker = (UIDocumentPickerViewController*)viewControllerToPresent;
}
[super presentViewController:viewControllerToPresent animated:flag completion:completion];
}
- (void)dismissViewControllerAnimated:(BOOL)flag
completion:(void (^)(void))completion
{
if (_docPicker != nil && self.presentedViewController == nil)
{
}
else
{
[super dismissViewControllerAnimated:flag completion:completion];
}
}
回答4:
Try this(working):
navigationController?.dismiss(animated: true, completion: nil)
来源:https://stackoverflow.com/questions/41085881/uidocumentpickerviewcontroller-dismisses-parent-view-controller