web-dev-qa-db-ja.com

UIWebViewEXC_BAD_ACCESSのクラッシュ

UIWebViewを使用するアプリのクラッシュが発生しています。通常、ページが完全にロードされておらず、UIWebViewにstopLoadingセレクターが送信されます。または、UIWebViewがページを完全にロードしたとき。私が持っている EXC_BAD_ACCESS。スタックは次のようになります。

#0  0x95bb7688 in objc_msgSend
#1  0x30a671db in -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
#2  0x3024a10d in __invoking___
#3  0x30249ff8 in -[NSInvocation invoke]
#4  0x358ab160 in HandleDelegateSource
#5  0x302452c1 in CFRunLoopRunSpecific
#6  0x30244628 in CFRunLoopRunInMode
#7  0x32044c31 in GSEventRunModal
#8  0x32044cf6 in GSEventRun
#9  0x309021ee in UIApplicationMain
#10 0x0000239c in main at main.m:13

私にとってここで最も奇妙なことはwebView:decidePolicyForNavigationAction:request:frame:decisionListener:セレクターはUIWebViewに送信されます。これは、UIWebViewドキュメントにそのようなセレクターがないためです。 Cocoaのみ(cocoa touchではない)WebView。 UIWebViewまたはそのデリゲートに問題があると思われます。しかし、それらを監視するためのブレークポイントを設定することはできません。この状況でより多くの情報を得る方法を教えてください。

29
HARDWARRIOR

ビューを離れる前に、webViewのロードを停止し、デリゲートを削除する必要があります。

// ARC (correct solution)
- (void)dealloc {
    [_webView setDelegate:nil];
    [_webView stopLoading];
}

// non ARC
- (void)dealloc {
    [webView setDelegate:nil];
    [webView stopLoading];
    [webView release];
    [super dealloc];
}

// ARC (older solution)
- (void)viewWillUnload {
    [webView setDelegate:nil];
    [webView stopLoading];
}

Appleドキュメントの内容:重要デリゲートを設定したUIWebViewのインスタンスをリリースする前に、まずデリゲートプロパティをnilに設定する必要があります。これは次のようになります。たとえば、deallocメソッドで実行されます。

86
Ondrej

NSZombieをオンにして、リリースが早すぎるかどうかを確認してください。

ビューの読み込みをキャンセルし、すぐにビュー階層を破棄して、UIWebViewがそれをいじる前に何かが解放されている可能性があります。

この場合、バックトレースは、早期にリリースされているデリゲートのようにはっきりと見えます。デリゲートの関係は通常弱く、GCがないため、このように見えるクラッシュを引き起こす参照をぶら下げるための素晴らしいソースです。

9
bbum

View Will Disappearは、受け入れられた回答に対する有効なオプションです。

// ARC
- (void)viewWillDisappear:(BOOL)animated{
    [self.webView setDelegate:nil];
    [self.webView stopLoading];
}

これはiOS6で完全に機能します。

5
jturolla

スクロールしているUIWebViewでEXC_BAD_ACCESSがクラッシュしていましたが、iPadでのみ、ユーザーがUIWebViewを含むViewControllerを閉じたときにスクロールを終了した場合に限りました。

デリゲートをnilに設定しても、ここでは問題は解決しませんでしたが、別の問題で他の場所で解決策を見つけました。このコードを、閉じるボタンによって呼び出されるメソッドに追加しました。

for (id subview in webView.subviews){
        if ([[subview class] isSubclassOfClass: [UIScrollView class]]){
            [subview setContentOffset:CGPointZero animated:NO];
        }
    }

これにより、deallocメソッドが呼び出される前にスクロールが停止しますが、これが問題のようです。

2
avance

また、この正確なエラーが発生しました。これは、UIWebViewに指定したデリゲートが保持されていないことが原因でした(私の場合はUIViewController)。

1
AustinRathe

Webビューからのデリゲートの登録解除の処理、およびWebビューのロードの停止の処理は、ViewControllerのdeallocメソッドから行うのが最適です。

viewWillDisappearが失敗する可能性がある場合の例として: ViewControllerが別のViewControllerの子である場合、アニメーションを使用して親ViewControllerのビューからViewControllerのビューの削除をトリガーできます。同時に、ViewControllerをその親から削除し、その参照をゼロにすることができます。その時点で、ViewControllerはnilになり、viewWillDisappearが呼び出されることはありません。つまり、WebViewデリゲートがクリーンアップされることはありません。

Deallocを使用して、WebViewが常にクリーンアップされていることを確認してください。

0
Fostah