31

私はグーグルマップをロードしているUIWebViewを含むビューを持っています(たくさんのjavascriptなど)。私が抱えている問題は、Webビューの読み込みが完了する前にユーザーがナビゲーションバーの「戻る」ボタンを押すと、Webビューに読み込みを停止してから解放するように、取得せずにきちんと指示する方法が明確でないことです。割り当て解除されたインスタンスに送信されるメッセージ。また、Webビューが、コンテナビューが完了する前に消えることを好むかどうかもわかりません(ただし、ユーザーがロードする前に戻るボタンを押すかどうかは選択できません)。

私のviewWillDisappearハンドラーで私はこれを持っています

map.delegate=nil;
[self.map stopLoading];

デリゲートをnilすると、ビューコントローラへのdidFailLoadWithErrorの送信が停止するため、これでほとんどの場合は問題なく処理されるようです。ただし、ビューのdeallocメソッドでWebビューを解放すると、場合によっては(断続的に)、実際のページで実行されているjavascriptに関連しているように見える、割り当て解除されたインスタンスにメッセージが送信されます。

-[UIWebView webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:]: message sent to deallocated instance 0x4469ee0

単にWebビューを解放しないと、Webビューがリークしていると思いますが、これらのメッセージは表示されません。

'stopLoading'メッセージを送信せず、viewWillDisappear内でWebビューを解放するだけの場合、次のようなメッセージが表示されます。

/SourceCache/WebCore/WebCore-351.9.42/wak/WKWindow.c:250 WKWindowIsSuspendedWindow:  NULL window.

おそらく関連して、私は時々(再び完全に断続的に)醜いheisenbugを取得し、他のビューのナビゲーションバーの戻るボタンをクリックするとタイトルがポップされますが、ビューはポップされません。言い換えると、スタックにビューnのタイトルが残っていますが、表示されているビューは引き続きビューn + 1です(その結果、この画面に閉じ込められ、ルートビューに戻ることができません-他の方向、つまり、より多くのビューをプッシュして、正しくポップされなかったビューにポップバックします。ルートビューだけではありません。唯一の方法は、アプリを終了することです)。また、同じビューでの同じ一連のプッシュとポップが正常に機能する場合もあります。

この特定のものは私を狂わせています。これは、Webビューが読み込まれる前にビューが消えることに関連している可能性があります。つまり、この場合、メモリに落書きしてビュースタックを混乱させる可能性があると思います。または、これは完全に無関係であり、どこか別のバグである可能性があります(デバッグビルドモードで再現できなかったため、gdbで表示できない場合にのみリリースビルド設定で発生します:-)。デバッグの実行から、私は何も過剰にリリースしているとは思いません。そして、ある時点でWebビューのあるビューにヒットした場合にのみトリガーできるように見えますが、その直後には発生しません。

4

6 に答える 6

53

これのバリエーションは、リークとゾンビの問題の両方を修正する必要があります。

- (void)loadRequest:(NSURLRequest *)request
{
    [self retain];
    if ([webView isLoading])
        [webView stopLoading];
    [webView loadRequest:request];
    [self release];
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
    [self retain];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    [self release];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    [self release];
}

- (void)viewWillDisappear
{
    if ([webView isLoading])
        [webView stopLoading];
}

- (void)dealloc
{
    [webView setDelegate:nil];
    [webView release];
    [super dealloc];
}
于 2009-05-05T23:09:51.487 に答える
1

対処方法はいくつかありますが、これでうまくいくはずです。didFailLoadWithError メッセージが必要です。これは、停止したことを示しています。

フラグを設定する isLeaving=YES; Webview に stopLoading を送信します。

didFailLoadWithError: で、webview が停止したときに発生するエラーを確認します。

if ((thiserror.code == NSURLErrorCancelled) && (isLeaving==YES)) {

[otherClass performSelector:@selector(shootWebview) withObject:nil withDelay:0]

}

shotWebview で webView を解放します。


バリエーション: それについて無頓着になりたい場合は、[fillintheblank] の遅延で performSelector:withObject:withDelay: を実行できます。チェックなしで 10 ~ 30 秒呼び出します。ただし、ほぼ確実に回避できます。お勧めしません。

didFailLoadWithError にフラグを設定して、別の場所でクリーンアップすることができます。

または私のお気に入りです。おそらく、離れるときにすべての割り当てを解除する必要はありません。そのビュー コンテナを再び表示することはありませんか? それを再利用してください。

デバッグはリリースの問題とは異なるため、構成をチェックして、まったく同じであることを確認することをお勧めします。報奨金は、質問の再現可能な部分にありましたよね? ;-)。

-- ちょっと待ってください。WebView で View コンテナ全体を削除している可能性があります。上記のバリエーションを実行して、shootWebView でコンテナー全体を解放するのを待つことができます。

于 2009-05-03T07:47:20.283 に答える
1

投稿の後半で説明している UINavigationController のバグは、メモリ警告の処理に関連している可能性があります。私はこの現象を経験しており、スタック内のビュー (n+1) を表示しているときにメモリ警告をシミュレートすることで、スタック内のビュー n で再現できました。

UIWebView はメモリを消費するため、ビュー階層の一部として使用すると、メモリの警告が表示されても驚くことはありません。

于 2009-06-30T16:29:17.850 に答える
0

OS3でUIWebViewを使用してこれと同様の問題がありました.

サンプル コード (受け入れられた回答 - 上記) を読むと、やり過ぎのように思えます。たとえば、 [webView release] と webView = nil の行は、変数が宣言されていると作成者が説明する方法を考えると、まったく同じことを行います (したがって、両方は必要ありません)。また、retain と release のすべての行に完全に納得しているわけではありませんが、マイレージは異なると思います。

于 2009-08-17T14:34:18.887 に答える
0

簡単なreleaseメッセージでdealloc十分です。

あなたの 2 番目の問題は、時期尚早に割り当て解除されたビューのように聞こえますが、コードを見ずに多くを語ることはできません。

于 2009-04-26T02:35:57.987 に答える
-1

おそらく関連して、他のビューのナビゲーションバーの戻るボタンをクリックすると、ビューではなくタイトルがポップアップするという醜いハイゼンバグが発生することがあります(これも完全に断続的です)。言い換えると、スタックにビュー n のタイトルが残っていますが、表示されているビューはまだビュー n+1 です (結果として、この画面に閉じ込められ、ルート ビューに戻ることができません。他の方向、つまり、より多くのビューをプッシュして、ルート ビューではなく、正しくポップされなかったビューにポップ バックします。唯一の方法は、アプリを終了することです)。それ以外の場合は、同じビューでのプッシュとポップの同じシーケンスが正常に機能します。

スタックが 2 を超え、現在のビュー コントローラー インデックスが 2 を超えるナビゲーション コントローラーを使用している場合、この瞬間に memoryWarning が発生すると、同じ問題が発生します。

解決策は 1 つしかありません。NavigationController で pop および push メソッドをオーバーライドし、View Controller のスタックを使用し、スタックされた ViewController のビューとスーパービューを使用するなど、多くの実験を行った後に見つけたソリューションです。

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

@interface FixedNavigationController : 
UINavigationController <UINavigationControllerDelegate>{

}

@end

#import "FixedNavigationController.h"

static BOOL bugDetected = NO;

@implementation FixedNavigationController

- (void)viewDidLoad{
    [self setDelegate:self];
}

- (void)didReceiveMemoryWarning{
    // FIX navigationController & memory warning bug
    if([self.viewControllers count] > 2)
        bugDetected = YES;
}

- (void)navigationController:(UINavigationController *)navigationController 
didShowViewController:(UIViewController *)viewController 
animated:(BOOL)animated
{

    // FIX navigationController & memory warning bug
    if(bugDetected){
        bugDetected = NO;

        if(viewController == [self.viewControllers objectAtIndex:1]){
            [self popToRootViewControllerAnimated:NO];
            self.viewControllers = [self.viewControllers arrayByAddingObject:viewController];
        }
    }
}

@end

スタック内の 3 つのビュー コントローラーで正常に動作します。

于 2009-09-08T07:33:18.357 に答える