Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ios8 iPad uiwebview crashes while displaying popover when user taps drop down list HTML select tag

On ios8 and iPad if a uiwebview is displaying a HTML page containing a drop down list

eg this page http://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select

then

  • repeatedly tap on the HTML drop down list that contain lists of cars . first item is Volvo.
  • tap every 1/2 second or so that uipopover opens and closes
  • app will crash:

Terminating app due to uncaught exception 'NSGenericException', reason: 'UIPopoverPresentationController () should have a non-nil sourceView or barButtonItem set before the presentation occurs.'

Is there anyway to work around this in uiwebview in ios8?

It doesn't happen using wkwebview, but I would like to fix it in uiwebview.

Update: This seems to help but unsure of side effects. I have overridden the following in the view controller that contains the uiwebview.

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

    [super dismissViewControllerAnimated:NO completion:nil];
}
like image 291
seeinvisible Avatar asked Sep 18 '14 09:09

seeinvisible


4 Answers

The solution mentioned in the question did not help me, however it did point me in the right direction. After some investigation I would say it's some sort of race condition between presenting and removing the popover. As a workaround you can postpone the presentation in the delegate of the 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];
               });
}
like image 114
dogsgod Avatar answered Oct 21 '22 19:10

dogsgod


The previous solutions did not help me.

There is a bug already logged to Apple (see openradar) for this.

The issue seems to be that the web view tries to present a view controller in a popover without setting the sourceView of the popover. Although it's definitely an Apple issue I have used the following workaround to avoid my app to crash:

- (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];
}
like image 21
tanzolone Avatar answered Oct 21 '22 20:10

tanzolone


I worked around it in the following way after noticing that sourceView is set in the cases where it crashes:

-(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];
  }
}
like image 22
Daz Eddy Avatar answered Oct 21 '22 20:10

Daz Eddy


I had different exception in the same scenario, and none of workarounds from here helped me.

This was my exception:

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

This is code I used to workaround it:

-(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];
}

It's very nasty workaround that prevents from showing dropdown in cases when it's about to crash, and this solution can stop working in any time as it uses internal properties. However it was the only solution that worked for me so maybe it will be helpful for someone.

like image 1
marcin93w Avatar answered Oct 21 '22 21:10

marcin93w