objective c - segun - ios8 iPad uiwebview se bloquea al mostrar una ventana emergente cuando el usuario pulsa la lista desplegable etiqueta de selección de HTML
lista de opciones html (5)
He disminuido la probabilidad de que ocurra una falla de esta manera. Código javascript usado e ios nativo
Cambios en el código web
- Registre un detector de eventos ''clic'' en su componente html (desplegable).
- En el método de devolución de llamada enviar notificación a código nativo. ej: "
window.location=''fromJavaScript://PopoverIssue'';
" -
shouldStartLoadWithRequest
uiwebviewsshouldStartLoadWithRequest
Cambios en el código del lado nativo
- Implementar el protocolo
UIPopoverPresentationControllerDelegate
en viewcontroller que tiene uiwebview and over ridepopoverPresentationControllerShouldDismissPopover popoverPresentationControllerDidDismissPopover
- ponga el código a continuación en el método shouldStartLoadWithRequest de uiwebview para la notificación de clic anterior
[[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]; } }); });
implementar los métodos de protocolo anulados de la siguiente manera
(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]; } }); }); }
Espero que ayude a disminuir la ocurrencia del accidente.
En ios8 y iPad si uiwebview
muestra una página HTML que contiene una lista desplegable
por ejemplo, esta página http://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select
entonces
- toque repetidamente la lista desplegable de HTML que contiene listas de autos. El primer artículo es Volvo.
- toque cada 1/2 segundo o para que uipopover se abra y cierre
- la aplicación se bloqueará:
La aplicación se cerró debido a la excepción no detectada ''NSGenericException'', motivo: ''UIPopoverPresentationController () debe tener un código fuente no nulo SourceView o barButtonItem establecido antes de que se produzca la presentación.''
¿Hay uiwebview
evitar esto en uiwebview
en ios8?
No sucede usando wkwebview
, pero me gustaría arreglarlo en uiwebview
.
Actualización: Esto parece ayudar pero no está seguro de los efectos secundarios. He anulado lo siguiente en el controlador de vista que contiene el uiwebview.
-(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
{
if (completion)
{
completion();
}
[super dismissViewControllerAnimated:NO completion:nil];
}
La solución mencionada en la pregunta no me ayudó, sin embargo, me indicó la dirección correcta. Después de una investigación, diría que es una condición de carrera entre la presentación y la eliminación de la ventana emergente. Como solución puede posponer la presentación en el delegado de 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];
});
}
Las soluciones anteriores no me ayudaron.
Hay un error ya registrado en Apple (ver openradar ) para esto.
El problema parece ser que la vista web intenta presentar un controlador de vista en una ventana emergente sin configurar la vista de fuente de la ventana emergente. Aunque definitivamente es un problema de Apple, he usado la siguiente solución para evitar que mi aplicación se bloquee:
- (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];
}
Lo resolví de la siguiente manera después de notar que sourceView está configurado en los casos en que se bloquea:
-(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];
}
}
Tuve una excepción diferente en el mismo escenario, y ninguna de las soluciones de aquí me ayudó.
Esta fue mi excepción:
Terminating app due to uncaught exception ''NSRangeException'', reason: ''-[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:]: row (4) beyond bounds (0) for section (0).''
Este es el código que utilicé para solucionarlo:
-(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];
}
Es una solución muy desagradable que evita mostrar el menú desplegable en los casos en que está a punto de fallar, y esta solución puede dejar de funcionar en cualquier momento, ya que utiliza propiedades internas. Sin embargo, fue la única solución que funcionó para mí, así que quizás sea útil para alguien.