UIDocumentPickerViewController отклоняет родительский контроллер представления

У меня есть WKWebView в контроллере представления. Когда пользователь нажимает кнопку «Загрузить файл» (которая находится на показанной веб-странице), появляется UIDocumentPickerViewController. Это ожидаемо и совершенно необходимо, но:

Всякий раз, когда пользователь нажимает любую кнопку («Загрузить фото или видео», «Отмена»), UIDocumentPickerViewController закрывает себя И родительский контроллер представления, в котором он находится.

Я добавил символическую точку останова для [UIViewController dismissViewControllerAnimated:completion:] и действительно увидел, что -dismissViewController... вызывается дважды. После первого раза он отбрасывает UIDocumentPickerViewController, после второго — мой родительский вью-контроллер.

Кстати на айпаде проблем нет, наверное потому что UIDocumentPickerViewController представлено как поповер.

Почему это происходит и что мне делать?

Спасибо!


person Kansway    schedule 11.12.2016    source источник
comment
Я тоже это вижу, вы смогли решить?   -  person Tim Johnsen    schedule 03.01.2017
comment
Хорошо, я даже смог воспроизвести это в очень простом примере проекта. Для этого я подал радар с идентификатором # 29853806, включил этот образец проекта и это демонстрационное видео об ошибке.   -  person Tim Johnsen    schedule 04.01.2017
comment
Хм, у меня обратная проблема: presentingViewController закрывается, когда я нажимаю вне всплывающего окна. ????   -  person bio    schedule 06.09.2017


Ответы (4)


Хорошо, кажется, я нашел способ это исправить. WebKit является открытым исходным кодом, и вы можете видеть, что нарушающим правила является класс WKFileUploadPanel, в частности, _dismissDisplayAnimated: method вызывается слишком агрессивно, непреднамеренно вызывая отклонение вашего контроллера представления. Чтобы избежать этого, вам нужно заблокировать вызовы -dismissViewControllerAnimated:completion:, поступающие от WKFileUploadPanel, что вы можете сделать, просмотрев стек. Вот реализация, которая решает эту проблему.

Упомянутое выше решение не работает, потому что оно основано на просмотре символов стека вызовов для определенного класса, который запутывается при работе на реальном устройстве. Вот другой подход, который я использовал для решения этой проблемы:

  1. Добавьте свойство weak UIDocumentMenuViewController в класс контроллера модального представления.
  2. Переопределите -presentViewController:animated:completion: в своем модальном классе, чтобы проверить, является ли представленный контроллер представления UIDocumentMenuViewController, если это так, установите его как значение для вашего слабого свойства с шага 1.
  3. Переопределите -dismissViewControllerAnimated:completion:, чтобы проверить, является ли ваше слабое свойство nil, если оно не nil, а presentedViewController вашего модального окна равно nil, тогда это означает, что WebKit пытается отклонить ваше модальное окно, когда оно не должно быть. Вы можете не вызывать super в этом случае и продолжать вызывать его в противном случае.

Вы также можете просмотреть _dismissDisplayAnimated: от WKFileUploadPanel. метод, чтобы быть более осторожным с вашими собственными контроллерами представления, но это сопряжено со значительным риском.

person Tim Johnsen    schedule 04.01.2017

Я столкнулся с той же проблемой и, наконец, мне удалось найти обходной путь.

В моем контроллере представления я переопределяю метод dismiss для удаления управляемого объекта, если кнопка сохранения не была нажата, и это отлично работало с UIImagePickerController.

Поскольку мое приложение использует UIDocumentPickerViewController, мой управляемый объект удалялся каждый раз, когда вызывался documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL), потому что это вызывает ошибку presentingViewController.dismiss.

Поэтому мое решение состоит в том, чтобы проверить из presentingViewController, является ли presentedViewController nil, или не знать, был ли метод dismiss вызван UIDocumentPickerViewController или нет.

Итак, вот мой переопределенный метод dismiss из моего контроллера представления.

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

Надеюсь, это поможет вам.

person Shkelzen    schedule 04.08.2017

Я столкнулся с той же проблемой. Это происходит при использовании средства выбора документов и возникает в версиях iOS ниже 11.4. Используйте приведенный ниже код везде, где вы используете средство выбора документов. Из того, что я читал на разных форумах, есть проблема со средством выбора документов, и она была исправлена ​​​​в более поздних версиях iOS.

Объявите слабое свойство средства выбора документов.

@property (weak, nonatomic) UIDocumentPickerViewController *_Nullable docPicker;

Затем реализуйте методы делегата контроллера представления:

- (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];
    }
}
person Sateesh Pasala    schedule 10.06.2019

Попробуйте это (работает):

navigationController?.dismiss(animated: true, completion: nil)
person Romit Kumar    schedule 21.03.2018