10

UIWebViewが引き起こしている一連のリークを修正しようとしていますが、その原因も回避策も見つかりません。私がしていることは、ネットワーク リクエストを介して Web からコンテンツを取得し、HTML を組み立ててその場でロードすることです。

NSString* body = <some HTML>;
NSString* html = [NSString stringWithFormat:kHTMLTemplate, [self scripts], [self styles], body];
[_webView loadHTMLString:html
               baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];

新しいコンテンツが利用可能になるたびに、loadHTMLString再度実行して Web ビューを更新します。同じ Web ビュー、同じコントローラー、同じものをすべて再利用します。

Instruments は、リークされたすべてのオブジェクトがさまざまなサイズの General-block であり、それらのいずれにも情報が添付されていないという非常に奇妙なパターンを示します責任のあるライブラリ、責任のあるフレームなどはありません。実行されるたびloadHTMLStringに、新しいリークが追加されます。

UIWebViewメモリリークについてSOにはいくつかのスレッドがあるようです。見つかったすべての提案を試しました (たとえば、NSURLCacheをゼロに設定するか、リセットします。既存の UIWebView を解放して、新しいデータがあるたびに新しいものを割り当てるなど)、何も役に立ちませんでした。

これまでの私の調査では、1 つの明確な結果が導き出されました。ビューにロードした HTML に Javascript が含まれている場合にのみ、リークが存在するようです。上記の文字列に気付いた場合html、それはいくつかのコンポーネントで構成されています。1 つは[self scripts]単純に返す関数です。

return @"<script type='text/javascript' src='jquery-1.4.4.min.js'></script>"
        "<script type='text/javascript' src='jmy.js'></script>";

これを取り除けば、漏れはありません。<script>しかし、 HTML にタグを追加するとすぐにリークが発生します。jqueryファイル(またはこれに関しては他のjsファイル)を単純に含めると、それらも表示されます。

return @"<script type='text/javascript' src='jquery-1.4.4.min.js'></script>";

そこで質問ですが、ここで何が起きているか知っている人はいますか? 明らかに Javascript ファイルを HTML に含めると、UIWebViewメモリ リークが発生します。

UIWebView同じオブジェクトを再利用するとき、またはコンテンツを取得するたびに新しいオブジェクトをインスタンス化するときにリークが発生するという事実は、リークにつながる javascript ファイルの処理方法に何かがあるに違いないと考えさせられますloadHTMLString

これを修正する方法を知っている人はいますか?

ここに画像の説明を入力

4

1 に答える 1

11

何が起こっているのか、そして何よりも共有したい回避策についての手がかりをようやく見つけました。

JavaScript ファイルを単にインクルードしただけで、Web ビューのリロード時にメモリ リークが発生していたことを確認できます。UIWebViewHTML コンテンツを含むファイルを作成してから、それをthroughにロードし、 ;loadRequestを介して再ロードすることさえ試みました。reload漏れは常にそこにありました。そのためのレーダーを投稿します。

私を救ったinnerHTMLのは、Web ビューのコンテンツを更新するために使用していたことです。reloadまたはに依存する代わりにloadHTMLString、空の本文で Web ビューを初期化し (つまり、head必要なすべての JS/CSS ファイルを含むセクションがそこにありました)、設定を更新しましたdocument.body.innerHTML

body = [body stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"setBody(\"%@\");", body]];

setBody を次のように定義します。

var setBody = function(body) {
    document.body.innerHTML = body;
}

私は 2 つの利点を得ました。Web ビューの更新が非常に高速になったこと (これは DOM を更新しないことの影響であり、全体としては完全に望ましいとは言えません)、Instruments でアプリを実行してもメモリ リークはありませんでした。欠点は、アプリが正常に動作しているいくつかの条件を微調整する必要があったことです。具体的には:

  1. Web ビューの読み込みには (ボディ ページが空の場合でも) 時間がかかるため、そのコンテンツの最初の更新を DOM の準備ができたときに同期する必要があります。

  2. webViewDidFinishLoading信頼できないようです: にdocument.readyStateなる前に実行されcompleteます。

  3. document.documentElement.height、ページの高さを取得する公式の方法も信頼できないようです。回避策は、bodyパーツの「計算されたスタイル」を取得し、そのheight値を読み取ることです。

これが、自分の Web ビューでメモリ リークが発生していることに気付いた他の人の助けになることを願っています。

于 2012-08-07T15:39:18.380 に答える