I am trying to fix a bunch of leaks that my UIWebView
is causing and cannot find their origin nor a workaround. What I do is getting some content from the web through a network request, then assemble my HTML and load it on the fly:
NSString* body = <some HTML>;
NSString* html = [NSString stringWithFormat:kHTMLTemplate, [self scripts], [self styles], body];
[_webView loadHTMLString:html
baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
Each time there is new content available, I execute loadHTMLString
again to refresh the web view. I reuse the same web view, same controller, same everything.
Instruments shows a very strange pattern in which all leaked objects are General-blocks of various sizes and none of them has any information attached to it: no responsible library, no responsible frame, etc. Each time loadHTMLString
is executed, new leaks are added.
It seems that there are several threads in S.O. about UIWebView
leaking memory. I have tried all suggestions I found (e.g., setting the NSURLCache
to zero, or resetting it; I tried releasing the existing UIWebView and allocate a fresh one each time I have new data, etc.) but nothing has helped.
My investigations up to now lead to one clear outcome: it seems that the leaks are only present if the HTML I load into the view contains some Javascript. If you notice the html
string above, it is made up of several components; one is [self scripts]
which is a function that simply returns:
return @"<script type='text/javascript' src='jquery-1.4.4.min.js'></script>"
"<script type='text/javascript' src='jmy.js'></script>";
If I remove this, no leaks are there. But the leaks appear as soon as I add a <script>
tag to my HTML. They even appear if I simply include the jquery file (or any other js file, as to this):
return @"<script type='text/javascript' src='jquery-1.4.4.min.js'></script>";
So, the question: has anyone an idea about what is happening here? Clearly including a Javascript file into my HTML is making the UIWebView
leak memory.
The fact that leaks appear both when I reuse the same UIWebView
object or when I instantiate a new one each time I have content, leads me to think that there must be something in the way javascript files are handled by loadHTMLString
which leads to the leaks.
Does anyone know how this could be fixed?
I finally found some clue at what is happening and above all a workaround that I would like to share.
I can confirm that the simple inclusion of some javascript file was causing a memory leak on reload of the web view. I even tried building a file with the HTML content, then loading it into the
UIWebView
throughloadRequest
, and reloading it throughreload
; the leaks were always there. I will post a radar for that.What saved me was using
innerHTML
to update the content of the web view. Instead of relying onreload
orloadHTMLString
, I initialized my web view with an empty body (I mean, thehead
section was there, including all required JS/CSS files) then updated it settingdocument.body.innerHTML
:with setBody defined like this:
I obtained two benefits: the web view update became really fast (this is an effect of not updating the DOM, which on the other hand is not entirely desirable on the whole), and there were no memory leaks were running the app under Instruments. The drawback was that I had to fine-tune a couple of conditions where the app was running fine; specifically:
loading the web view (even with an empty body page) take a lot, so you have to synchronize the first update of its content to when the DOM is ready;
webViewDidFinishLoading
seems not reliable: it is executed beforedocument.readyState
becomescomplete
;document.documentElement.height
, the official way of retrieving the page height seems not reliable, too: workaround is getting the "computed style" of thebody
part and read itsheight
value.Hope this helps someone else who finds that his web views are leaking memory.