2009-04-26 16 views
31

GoogleマップをロードしているUIWebViewを含むビューがあります(たくさんのjavascriptなど)。私が持っている問題は、Webビューの読み込みが完了する前にユーザーがナビゲーションバーの「戻る」ボタンを押すと、Webビューに読み込みを停止してから解放する方法をわかりやすく伝えることができないということです割り当て解除されたインスタンスに送信されたメッセージ私はまた、Webビューが完了する前にそのコンテナの表示が消えているのを確信していません(しかし、ユーザーがロードされる前に戻るボタンを押した場合は選択肢がありません)。viewWillDisappearでUIWebViewを安全にシャットダウンする方法は?

私はこの

を持っている私のviewWillDisappearハンドラで

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

デリゲートをnil'ingすると、それは私のビューコントローラにdidFailLoadWithErrorの送信を停止しますので、これは、OKほとんどのケースを扱うようです。しかし、私のビューのdeallocメソッドでWebビューを解放すると、時々(間欠的に)、解放されたインスタンスにメッセージが送られます。実際のページで実行されているjavascriptに関連しているようです(例:

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

私は単にwebviewを公開しないと、私はこれらのメッセージを受け取っていませんが、私はwebviewを漏洩していると思います。

私は「stopLoading」メッセージを送信し、単にviewWillDisappear内のWebViewをリリース、その後、私はこのようなメッセージが表示されない場合:

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

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

この特定の1つは私をナットに追いやっています。 Webビューがロードされる前に消えていくビューに関連している可能性があります。つまり、このケースでは、メモリ上で不安定になり、ビュースタックを混乱させる可能性があります。あるいは、これは完全に無関係かもしれず、どこか別のバグかもしれません(私はデバッグビルドモードでこれを再現できませんでした。リリースビルドの設定ではgdbで見ることができません:-)。私のデバッグの実行から、私は何も公開していないとは思わない。そして、ある時点で私がWebビューを持っているビューに当たったときに、それを引き起こすことができるように思えるだけで、その直後には発生しません。

+3

私があなたの場合は、Appleにバグを報告します。 Webビューは、割り当てが解除された後でメッセージを受け取るべきではありません.DeallocされたときにJS処理とURL読み込みを終了する必要があります。私はnavアイテムの問題を時々見たことがあるが、iPhone OS 3.0ベータ版をインストールした後でしかない。多分それはOSのバグでしょうか? –

+0

それは私が思ったことです(deallocはきれいにすべきです)。リンゴのドキュメントは、彼らが提供するオブジェクトとの契約では一般的にはあまり明確ではありません。私は前にナビのことを見たことがないし、私はそれが私がやっている必要があります - 私はそれを修正することができればうまくいけばこのwebview事に関連していると思う私のプログラムで十分に定期的に発生します。 – frankodwyer

+0

ohと追加するには、これが2.2.1で発生します – frankodwyer

答えて

52

この上の変化は、漏れやゾンビの問題の両方を解決する必要があります。私はこの現象を経験しました。スタック内のビュー(n + 1)を見ながらメモリ警告をシミュレートすることで、スタック内のビューnに再現できました。

UIWebViewはメモリを使うので

+0

はい良い答え、私はこれのようなものを試すことを考えていた。あなたの答えには私が思っていないことがいくつかありますので、試してみて、それがうまくいくなら私はこれを受け入れます。残念ながら、私はこれを試す時間を得る前に賞金は期限切れになります - しかし、私がすることは、奨励金を再開し、その場合の回答を受け入れることです(私に思い出させるには、250の賞金です)。 – frankodwyer

+0

私は恩恵についてあまり心配しません。それはちょうど数字です(しかも、とにかくトップの答えに半分が与えられます)。 – rpetrich

+0

最終的にこれを試してみました。面白いメッセージがなくても、それはひめんばんを治したようだ - かなり断続的だったので、もう少しテストしてみるまで、私はまだ応援しません。 – frankodwyer

0

releaseのメッセージdeallocで十分であるはずです。

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

+0

はい簡​​単deallocのリリースは、私が持っていたもので、これは、メッセージが解放されたインスタンスに送られる結果になります。 webviewは@property(nonatomic、retain)で宣言されています。また、私はNSZombieのチェックをしています。そうしないと、ビューを割り当て解除するメッセージが表示されません。また、デバッグモードではこれを再現することはできません。リリースモードでのみ発生します。 – frankodwyer

1

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

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

:, のWebViewが停止したときにあなたが得るエラーのチェック:

場合((thiserror。コード== NSURLErrorCancelled)& &(isLeaving == YES)){

[otherClass performSelector:@selector(shootWebview)withObject:ゼロのwithDelay:0]

}

shootWebview内のWebViewを放出します。


バリエーション: あなたはそれについて無頓着になりたい場合は、あなたがperformSelectorを行うことができます:withObject:withDelay:[fillintheblank]、それを呼び出す10-30セコの遅れで私はそれをお勧めしませんが、チェックなしであなたはほとんど確実にそれを得るでしょう。

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

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

あなたのデバッグはリリースの問題とは異なりますので、設定が正しいことを確認してください。バウンティは質問の再現可能な部分にあったのですよね? ;-)。

- ああ、少し待つと、ViewView全体をWebViewで表示している可能性があります。上のバリエーションを実行し、shootWebViewでコンテナ全体を解放するまで待つことができます。あなたのポストの第二の部分に記述しているUINavigationControllerのバグは、メモリの警告をお取り扱いに関連するかもしれない

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

私の問題は、viewWillDisappearメッセージが表示されると、ビューコントローラが消えてしまい、まもなく割り当て解除されます(それに含まれるすべてのもの、つまりwebview)。私はそれを行う私ではないので、ビューコントローラが(それを漏れることなく)割り当て解除されることを防ぐための方法は表示されません。したがって、任意のデリゲートメッセージは、コントローラの解放されたインスタンスに(時には)送られます。 – frankodwyer

+0

これは私が入力したときでもうねっているようですが、didfinishloadとdidfailloadsの[web release loading]の前に[self retain]を実行して[self release]でバランスをとって、WebViewsが正しく完了するまですべてがスティックされることを確認します。 – dieselmcfadden

+0

はい、私は自分自身のラインに沿って考えていた、あなたのように私はそれがちょっとばかげたと思った - それがうまくいかない理由を見ないでください。 rpetrichの答えのラインに沿って、これを試してみましょう。 – frankodwyer

1

+0

これは面白いです、ありがとう。私はメモリ警告(私はまったくそれを扱わない)に応答して何をしたいのかを読み上げます。私は3.0に移動してmapviewに賛成してwebviewを投げ捨て、一般的にメモリ処理の他の領域を強化して以来、私は実際にこの問題を見ていませんでした。 – frankodwyer

0

私はOS3のUIWebViewを使って同様の問題を抱えていましたが、この記述は良い出発点でしたが、単純にnil'ing私の問題を解決したwebViewをリリースする前に、Webビューのデリゲートを外してください。

サンプルコードを読んでいれば(上記の受け入れられた回答 - 上記のように)、WebViewのリリースとwebView = nil lines do作者が変数を記述する方法とまったく同じものが宣言されています(したがって、両方を必要としません)。私はまた、すべての保持ラインとリリースラインのどちらかに完全には納得していませんが、あなたの走行距離は変わると思います。 memoryWarningこのmomensで発生した場合

0

Possibly related, I sometimes (again totally intermittent) get an ugly heisenbug where clicking the back button on some other view's navbar will pop the title, but not the view. In other words I get left with the title of view n on the stack, but the view showing is still view n+1 (the result is you're trapped on this screen and cannot get back to the root view - you can go the other direction, i.e. push more views and pop back to the view that didn't pop corrrectly, just not to the root view. The only way out is to quit the app). At other times the same sequence of pushes and pops on the same views works fine.

私はスタック> 2と現在のビューコントローラインデックス> 2のビューコントローラで使用するナビゲーションコントローラだとき、私は、同じ問題を抱えているが、それは同じ問題を提起します。

多くの実験の後、NavigationControllerのオーバーライドポップとプッシュメソッドで、View Controllerのスタック、スタックされたViewControllersのビューやスーパービューなどで、1つの解決策が見つかりました。

#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つのビューコントローラの正常に動作します。

関連する問題