Утечки памяти с помощью UIWebView и Javascript
Я пытаюсь исправить кучу утечек, которые вызывает мой UIWebView
и не может найти их происхождение или обходной путь. Я получаю некоторый контент из Интернета через сетевой запрос, а затем собираю свой 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
, чтобы обновить веб-представление. Я использую один и тот же веб-вид, тот же самый контроллер, то же самое.
Инструменты показывают очень странный шаблон, в котором все просочившиеся объекты являются общими блоками разных размеров, и ни одна из них не имеет к нему никакой информации: никакой ответственной библиотеки, никакого ответственного кадра и т.д. Каждый раз, когда выполняется loadHTMLString
добавлены новые утечки.
Кажется, что существует несколько потоков в S.O. около UIWebView
утечки памяти. Я попробовал все предложения, которые я нашел (например, установив NSURLCache
в ноль или сбросив его, я попытался освободить существующий UIWebView и выделить новый каждый раз, когда у меня есть новые данные и т.д.), Но ничего не помогло.
Мои исследования до сих пор приводят к одному явному результату: кажется, что утечки присутствуют только в том случае, если HTML, который я загружаю в представление, содержит некоторый Javascript. Если вы заметили строку html
выше, она состоит из нескольких компонентов; один [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
, что приводит к утечкам.
Кто-нибудь знает, как это можно исправить?
![enter image description here]()
Ответы
Ответ 1
Наконец-то я нашел ключ к тому, что происходит, и, прежде всего, обходное решение, которое я хотел бы поделиться.
Я могу подтвердить, что простое включение некоторого файла javascript вызывало утечку памяти при перезагрузке веб-представления. Я даже попытался создать файл с содержимым HTML, затем загрузив его в UIWebView
через loadRequest
и перезагрузив его через reload
; утечки всегда были там. Я отправлю для этого радар.
Что меня спасло, я использовал innerHTML
для обновления содержимого веб-представления. Вместо того, чтобы полагаться на reload
или loadHTMLString
, я инициализировал свой веб-представление пустым телом (я имею в виду, что там был раздел 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;
}
Я получил два преимущества: обновление веб-просмотра стало очень быстрым (это эффект не обновления DOM, который, с другой стороны, не совсем желателен в целом), и не было утечек памяти, которые запускали приложение под Инструменты. Недостатком было то, что мне пришлось точно настроить несколько условий, в которых приложение работало нормально; а именно:
-
загрузка веб-представления (даже с пустой страницы тела) занимает много, поэтому вам нужно синхронизировать первое обновление своего содержимого с тем, когда DOM готов,
-
webViewDidFinishLoading
кажется ненадежным: он выполняется до document.readyState
становится complete
;
-
document.documentElement.height
, официальный способ получения высоты страницы тоже не является надежным: обходной способ получения "вычисленного стиля" части body
и чтения его значения height
.
Надеюсь, что это поможет кому-то еще, кто обнаруживает, что его веб-представления утечки памяти.