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];
}
Ответы
Ответ 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];
}
});
});
}
Надеюсь, что это поможет уменьшить возникновение аварий.