Подтвердить что ты не робот

Ios8 iPad uiwebview падает при отображении popover, когда пользователь бросает выпадающий список HTML select tag

На ios8 и iPad, если uiwebview отображает HTML-страницу, содержащую выпадающий список

например, эта страница http://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select

затем

  • повторно нажмите на раскрывающийся список HTML, содержащий списки автомобилей. первым пунктом является Volvo.
  • нажмите каждые 1/2 секунды или так, чтобы uipopover открывал и закрывал
  • произойдет сбой приложения:

Завершение приложения из-за неотображенного исключения "NSGenericException", причина: 'UIPopoverPresentationController () должен иметь не нуль sourceView или barButtonItem перед представлением. '

Есть ли способ обойти это в uiwebview в ios8?

Этого не происходит с помощью wkwebview, но я хотел бы исправить его в uiwebview.

Обновление: похоже, это помогает, но не знает о побочных эффектах. Я переопределил в контроллере представления, который содержит uiwebview.

-(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
{
    if (completion)
    {
        completion();
    }

    [super dismissViewControllerAnimated:NO completion:nil];
}
4b9b3361

Ответ 1

Решение, упомянутое в вопросе, не помогло мне, однако оно указало мне в правильном направлении. После некоторого расследования я бы сказал, что это какое-то состояние гонки между представлением и удалением popover. В качестве обходного пути вы можете отложить презентацию в делегате UIWebView:

-(void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_USEC), dispatch_get_main_queue(),
               ^{
                   [super presentViewController:viewControllerToPresent animated:flag completion:completion];
               });
}

Ответ 2

Предыдущие решения мне не помогли.

В Apple уже зарегистрирована ошибка (см. openradar).

Проблема заключается в том, что веб-представление пытается представить контроллер представления в popover без установки sourceView popover. Хотя это определенно проблема Apple, я использовал следующее обходное решение, чтобы избежать моего приложения:

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
    // Override this method in the view controller that owns the web view - the web view will try to present on this view controller ;)

    if (viewControllerToPresent.popoverPresentationController && !viewControllerToPresent.popoverPresentationController.sourceView) {
        return;
    }

    [super presentViewController:viewControllerToPresent animated:flag completion:completion];
}

Ответ 3

Я работал над этим следующим образом, заметив, что sourceView установлен в случаях, когда он сбой:

-(void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {

  UIPopoverPresentationController* pres = viewControllerToPresent.popoverPresentationController;

  if(pres.sourceView) {
    //log the fact you are ignoring the call
  }
  else {
    [super presentViewController:viewControllerToPresent animated:flag completion:completion];
  }
}

Ответ 4

У меня было другое исключение в том же сценарии, и ни один из обходных путей отсюда не помог мне.

Это было мое исключение:

Terminating app due to uncaught exception 'NSRangeException', reason: '-[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:]: row (4) beyond bounds (0) for section (0).'

Это код, который я использовал для его обхода:

-(void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
    if ([viewControllerToPresent respondsToSelector:NSSelectorFromString(@"_cachedItems")]) {
        if([viewControllerToPresent valueForKey:@"_cachedItems"] == nil) {
            if (completion != nil) {
                completion();
            }
            return;
        }
    }

    [super presentViewController:viewControllerToPresent animated:flag completion:completion];
}

Это очень неприятное обходное решение, которое препятствует показу раскрывающегося списка в случаях, когда он собирается сбой, и это решение может перестать работать в любое время, так как оно использует внутренние свойства. Однако это было единственное решение, которое работало для меня, поэтому, возможно, это будет полезно для кого-то.

Ответ 5

Я уменьшил вероятность возникновения аварии таким образом. Используемый код javascript и родной ios

Изменения кода веб-страницы

  • Зарегистрируйте прослушиватель событий 'click' для вашего html-компонента (выпадающего списка).
  • В методе обратного вызова отправьте уведомление на собственный код. ex: "window.location='fromJavaScript://PopoverIssue';"
  • Он выберет uiwebviews shouldStartLoadWithRequest

Изменения в исходном коде

  • Реализовать UIPopoverPresentationControllerDelegate протокол на viewcontroller, который имеет uiwebview и более ездить popoverPresentationControllerShouldDismissPopover popoverPresentationControllerDidDismissPopover
  • введите ниже код в методе toStartLoadWithRequest для uiwebview для указанного выше уведомления о клике
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
        self.popoverPresentationController = self.presentedViewController.popoverPresentationController;
        self.existedPopoverDelegate = [self.popoverPresentationController delegate];
        self.popoverPresentationController.delegate = self;
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
        dispatch_async(queue, ^{
            int64_t delay = 2.0;
            dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC);
            dispatch_after(time, dispatch_get_main_queue(), ^{
                if([[UIApplication sharedApplication] isIgnoringInteractionEvents])
                {
                    [[UIApplication sharedApplication] endIgnoringInteractionEvents];
                }
            });
        });
  • реализовать переопределенные методы протокола следующим образом

    
    
    
  • (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController { [self.existedPopoverDelegate popoverPresentationControllerShouldDismissPopover:popoverPresentationController]; return YES; }

(void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController { [self.existedPopoverDelegate popoverPresentationControllerDidDismissPopover:popoverPresentationController]; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_async(queue, ^{ int64_t delay = 2.0; dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC); dispatch_after(time, dispatch_get_main_queue(), ^{ if([[UIApplication sharedApplication] isIgnoringInteractionEvents]) { [[UIApplication sharedApplication] endIgnoringInteractionEvents]; } }); }); }

Надеюсь, что это поможет уменьшить возникновение аварий.