uiwebview
がドロップダウンリストを含むHTMLページを表示している場合のiOS8およびiPad
例:このページ http://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select
それから
キャッチされない例外 '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];
}
質問で言及された解決策は私を助けませんでしたが、正しい方向に私を指し示しました。いくつかの調査の後、ポップオーバーの提示と削除の間の何らかの競合状態だと思います。回避策として、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];
});
}
以前のソリューションは私を助けませんでした。
これについては、すでに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];
}
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];
}
}
同じシナリオで異なる例外がありましたが、ここからの回避策はありませんでした。
これは私の例外でした:
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];
}
クラッシュしようとしている場合にドロップダウンを表示しないようにする非常に厄介な回避策であり、このソリューションは内部プロパティを使用しているため、いつでも動作を停止できます。しかし、それは私のために働いた唯一の解決策だったので、多分それは誰かのために役立つでしょう。
このようにしてクラッシュが発生する可能性を減らしました。使用されたJavaScriptコードとネイティブiOS
Webサイドコードの変更
window.location='fromJavaScript://PopoverIssue';
"shouldStartLoadWithRequest
を呼び出しますネイティブサイドコードの変更
UIPopoverPresentationControllerDelegate
プロトコルを実装しますpopoverPresentationControllerShouldDismissPopover popoverPresentationControllerDidDismissPopover
[[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]; } }); }); }
クラッシュの発生を減らすのに役立つことを願っています。