web-dev-qa-db-ja.com

ユーザーがドロップダウンリストHTML selectタグをタップすると、popoverを表示しているときにios8 iPad uiwebviewがクラッシュする

uiwebviewがドロップダウンリストを含むHTMLページを表示している場合のiOS8およびiPad

例:このページ http://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select

それから

  • 車のリストを含むHTMLドロップダウンリストを繰り返しタップします。最初のアイテムはボルボです。
  • 1/2秒ごとにタップして、Uipopoverを開閉します
  • アプリがクラッシュします:

キャッチされない例外 'NSGenericException'によるアプリの終了、理由: 'UIPopoverPresentationController()は、プレゼンテーションが発生する前に、nil以外のsourceViewまたはbarButtonItemを設定する必要があります。

Ios8のuiwebviewでこれを回避する方法はありますか?

wkwebviewを使用しても発生しませんが、uiwebviewで修正したいと思います。

更新:これは役立つようですが、副作用は不明です。 uiwebviewを含むView Controllerで次をオーバーライドしました。

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

    [super dismissViewControllerAnimated:NO completion:nil];
}
42
seeinvisible

質問で言及された解決策は私を助けませんでしたが、正しい方向に私を指し示しました。いくつかの調査の後、ポップオーバーの提示と削除の間の何らかの競合状態だと思います。回避策として、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];
               });
}
42
dogsgod

以前のソリューションは私を助けませんでした。

これについては、すでにApple( openradar を参照)に記録されているバグがあります。

問題は、WebビューがポップオーバーのsourceViewを設定せずにポップオーバーでView Controllerを表示しようとすることです。それは間違いなく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];
}
9
tanzolone

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];
  }
}
1
Daz Eddy

同じシナリオで異なる例外がありましたが、ここからの回避策はありませんでした。

これは私の例外でした:

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

クラッシュしようとしている場合にドロップダウンを表示しないようにする非常に厄介な回避策であり、このソリューションは内部プロパティを使用しているため、いつでも動作を停止できます。しかし、それは私のために働いた唯一の解決策だったので、多分それは誰かのために役立つでしょう。

1
marcin93w

このようにしてクラッシュが発生する可能性を減らしました。使用されたJavaScriptコードとネイティブiOS

Webサイドコードの変更

  1. 「クリック」イベントリスナーをhtmlコンポーネントに登録します(ドロップダウン)。
  2. コールバックメソッドで、通知をネイティブコードに送信します。例: "window.location='fromJavaScript://PopoverIssue'; "
  3. Uiwebviews shouldStartLoadWithRequestを呼び出します

ネイティブサイドコードの変更

  1. Uiwebviewおよびover rideを持つviewcontrollerにUIPopoverPresentationControllerDelegateプロトコルを実装しますpopoverPresentationControllerShouldDismissPopover popoverPresentationControllerDidDismissPopover
  2. 上記のクリック通知のために、uiwebviewのshouldStartLoadWithRequestメソッドに以下のコードを入れます
    [[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];
                }
            });
        });
  3. オーバーライドされたプロトコルメソッドを次のように実装します



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

クラッシュの発生を減らすのに役立つことを願っています。

0
Uday Sravan K