uiwebview and memory crash (caching and memory useage)
ello fellow iphoners
im in a bit of a bad spot here, for the last week and a half, i have been trying to track down either a slow down in my app, or a crash, recently, in the last few days, i think i have realized what it is
UIWebView
and what a horrible monster it is
im basically pushing views into a uinavigation controller, and the last one to be pushed is a ui webview
UITableView in a uiview > UITableView in a uiview > uiview > UIWebView
the webview is asked to load a url, when you click the last uitablecell in the succession
the problem is seen in the webview as i have tracked it in recieves memory warning.
the uiwebview is being created programatically, and there are no leaks
i have heard that there are issues about uiwebview loading big pages, but crashing when in apps because it has run out of memory, and the delegate recieves a warning
now, my questions are
1. has anyone else seen this
2. is there any way to stop pages caching data, or taking up so much memory
3. is there anything i can do
thanks to those who reply to my problem
much appreciated (iphone app developer at his wits end)
To clarify, does the memory issue happen within a single UIWebView object, as you're loading multiple pages? Or does the memory increase over time as web views are being created and destroyed, as you push and pop view controllers throughout the lifetime of the app?
It's been a while since I've looked at this, but in a previous app we found that the web view class was internally leaking resources by not cleaning up after itself properly when destroyed. I don't remember all of the details, but I believe that the UIWebView would spawn a new thread the first time HTML was loaded, but the thread was never being stopped (and its memory never freed), even after the web view was destroyed. This wasn't an issue for a single web view, but in situations where web views were created and destroyed frequently, the memory usage would add up and eventually kill the app (although it did take a while). This was on earlier 3.0 OS versions, so I have no idea if things have changed in the newer updates.
Does this sound like the problem you're having? If so, I believe the only workaround we were able to find was to create a static webview object that would persist throughout the lifetime of the app, instead of creating and destroying web view objects as its view controller was pushed and popped. This seemed to prevent the issue described above. We never noticed any other issues, though, so if this isn't the problem you're experiencing then nothing else comes to mind.
when you say you create a webview throughout the whole existence of the app, you mean that you init a UIWebview in your root controller, and whatever view needs, calls the webview into its view, when the view is popped from a navigation stack, you just remove the webview, ready for later use, off course you set its delegate to nil and stop it loading before removing it.
my way, that i have changed to, i just have the webview in the single nib that i need to push into the stack, will this avoid the leak, or will it mean that each time i init the nib, i generate another thread.
when you say you create a webview throughout the whole existence of the app, you mean that you init a UIWebview in your root controller, and whatever view needs, calls the webview into its view, when the view is popped from a navigation stack, you just remove the webview, ready for later use, off course you set its delegate to nil and stop it loading before removing it.
my way, that i have changed to, i just have the webview in the single nib that i need to push into the stack, will this avoid the leak, or will it mean that each time i init the nib, i generate another thread.
thanks
I believe that each time you initialize the nib file, a new web view is created. Maybe I'm misunderstanding what you mean, but if the web view is in the nib for the view controller that is being pushed and popped, then yes, it will still be created and destroyed, and I don't think that will fix the problem. You could put it in the nib for the root view, and it should be OK as long as the root view is never destroyed (although it will still be released and then recreated in the case of a memory warning, but this should hopefully be rare). In this case, you'd have to pass the web view to each view controller that needed it, as you said in your last post.
When I said we created a static web view, I meant it literally; the quick fix was just to make a static variable in the view controller class that contained the web view, and make sure it was initialized only once. Something like:
The webView is never released, so its retainCount never hits zero, even after the view controller it's been added to has been destroyed. We only ever needed to access the web view from inside WebViewController, so using the static variable wasn't an issue for us.
I should add: regardless of how it's implemented, of course the real test is to watch object allocations/memory usage in instruments as you push and pop the view controllers containing web views. If you can do this for a while without any significant increases in memory, then you should be good.
basically, the way i am doing, the nib allocation still messes it up as it keeps being recreated, and therefore the webview reinitializes because i dealloc that specific view and its controller
now, here is the complicated part
1. the controller the navigation controller does get deallocated
2. the web controller is used inside the navigation controller
3. my structure is based like the following
mainController
>>childController
>>>>navigationcontroller
>>>>>>webcontroller
>>childcontroller
>>>>anothercontroller
.... and so on
so, i need to create the webview inside the mainController, because, it is never deallocated, they are all linked through a parent child relationship using assign properties, so i dont mind passing the request down the line to whomever needs it. Its complicated. I was required to create section sub section / sub sub sub section based navigation but it could not use the semantics of uinavigationcontroller. It all works super fine, except for this one problem.
Sounds like you have a handle on this now. Make sure you confirm that you fixed the problem in instruments. Also, if you have a small code sample or can easily make one that confirms the problem, it might be a good idea to submit a bug report to apple. The more people who report this, the faster it's likely to be fixed in a future update.
Sounds like you have a handle on this now. Make sure you confirm that you fixed the problem in instruments. Also, if you have a small code sample or can easily make one that confirms the problem, it might be a good idea to submit a bug report to apple. The more people who report this, the faster it's likely to be fixed in a future update.
chris, you definately helped me out here, thanks a lot.
i also noticed that you should load an empty string into the webview if the viewcontrollers in the stack are 1 after the other
now, if i go to controllerwithwebview, and then go to lastcontrollerwithwebview, i basically steal the webview from the previous viewcontroller, so i have to dump an empty string in there before calling the NSURLRequest for a website, and also when popping the stack back to the previous controller, i have to re insert the webview as it was stolen from it by the last controller
pheeewwww, hope that made sense.
anyways, you have been a great help man.
i will continue with testing in app and instruments to see if the problem is fixed, but it looks like it is.