2012-08-05 15 views
10

Estoy tratando de arreglar un montón de fugas que mi UIWebView está causando y no puedo encontrar su origen ni una solución alternativa. Lo que hago es conseguir un poco de contenido de la web a través de una solicitud de red, a continuación, montar mi HTML y cargarlo sobre la marcha:Fugas de memoria con UIWebView y Javascript

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

Cada vez que hay nuevo contenido disponible, ejecuto loadHTMLString de nuevo para actualizar la vista Web . Reutilizo la misma vista web, el mismo controlador, el mismo todo.

Instrumentos muestra un patrón muy extraño en el que todos los objetos son filtrados generales bloques de diferentes tamaños y ninguno de ellos ha de cualquier información que se le atribuye: ninguna biblioteca responsable, hay un marco responsable, etc. Cada vez que se ejecuta loadHTMLString , se agregan nuevas fugas.

Parece que hay varios hilos en S.O. acerca de UIWebView filtración de memoria. He intentado todas las sugerencias que encontré (por ejemplo, estableciendo NSURLCache en cero o restableciéndolo; intenté liberar el UIWebView existente y asignar uno nuevo cada vez que tengo datos nuevos, etc.) pero nada me ha ayudado.

Mis investigaciones hasta ahora conducen a un resultado claro: parece que las filtraciones solo están presentes si el HTML que cargo en la vista contiene algo de Javascript. Si observa la cadena anterior html, está formada por varios componentes; uno es [self scripts] que es una función que devuelve simplemente:

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

Si quito esto, no hay escapes allí. Pero las filtraciones aparecen tan pronto como agrego una etiqueta <script> a mi HTML. Incluso si simplemente parecen incluir el archivo de jQuery (o cualquier otro archivo js, ​​en cuanto a esto):

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

Entonces, la pregunta: ¿Alguien una idea acerca de lo que está sucediendo aquí? Claramente incluir un archivo Javascript en mi HTML está haciendo la memoria de pérdida UIWebView.

El hecho de que las fugas aparecen tanto cuando reutilizar el mismo UIWebView objeto o cuando una instancia de un nuevo cada vez que tenga contenido, me lleva a pensar que debe haber algo en la forma en archivos javascript son manejados por loadHTMLString que conduce a las filtraciones

¿Alguien sabe cómo esto podría solucionarse?

enter image description here

+0

Esto puede ser un error en UIWebView. http://blog.techno-barje.fr/post/2010/10/04/UIWebView-secrets-part1-memory-leaks-on-xmlhttprequest/ –

+0

@ H2CO3: gracias, también lo intenté ... sin mejoras. .. – sergio

+0

creo que estamos guardados por iOS 8. Consulte esta respuesta en WKWebView http://stackoverflow.com/questions/16514230/massive-memory-leak-in-ios-uiwebview –

Respuesta

11

fin he encontrado alguna pista de lo que está ocurriendo y, sobre todo, una solución que me gustaría compartir.

Puedo confirmar que la simple inclusión de algún archivo javascript estaba causando una pérdida de memoria al volver a cargar la vista web. Incluso intenté construir un archivo con el contenido HTML, luego lo cargué en UIWebView a través de loadRequest, y lo recargué a través de reload; las filtraciones siempre estuvieron ahí. Voy a publicar un radar para eso.

Lo que me salvó fue usar innerHTML para actualizar el contenido de la vista web.En lugar de confiar en reload o loadHTMLString, que inicializa mi punto de vista web con un cuerpo vacío (quiero decir, la sección head estaba allí, incluyendo todos los archivos JS requeridos/CSS), entonces actualizada que éste se ocultaba document.body.innerHTML:

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

con setBody se define así:

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

que obtienen dos ventajas: la actualización de la página we convirtió muy rápido (esto es un efecto de no actualizar el DOM, que por otra parte no es del todo deseable en general), y hay no hubo pérdidas de memoria ejecutando la aplicación en Instrumentos. El inconveniente fue que tuve que afinar un par de condiciones en las que la aplicación funcionaba bien; específicamente:

  1. cargar la vista web (incluso con una página de cuerpo vacío) tomar mucho, así que hay que sincronizar la primera actualización de su contenido para cuando el DOM está listo;

  2. webViewDidFinishLoading parece no fiable: se ejecuta antes de que se convierte en document.readyStatecomplete;

  3. document.documentElement.height, la forma oficial de la recuperación de la altura de la página parece no fiable, también: solución es conseguir que el "estilo computarizada" de la parte body y leer su valor height.

Espero que esto ayude a alguien más a encontrar que sus vistas web están perdiendo memoria.