I am currently building a navigation controller app in iOS 5.1 that uses ARC. I often need to display webpages and I have made a web viewer that is just a UIWebView with some custom content around the sides. When the user is finished looking at the page they hit the back button which should release all of the memory associated with the custom web viewer. My problem is that all of the memory does not appear to be released when the back button is hit. I have built a toy app (on github) that is just a couple of buttons each having a first responder that calls a different page.
@implementation ViewController
-(IBAction)googlePressed:(id)sender
{
CustomWebView *customWebView = [[CustomWebView alloc] initWithStringURL:@"http://www.google.com"];
[self.navigationController pushViewController:customWebView animated:NO];
}
-(IBAction)ksbwPressed:(id)sender
{
CustomWebView *customWebView = [[CustomWebView alloc] initWithStringURL:@"http://www.ksbw.com/news/money/Yahoo-laying-off-2-000-workers-in-latest-purge/-/1850/10207484/-/oeyufvz/-/index.html"];
[self.navigationController pushViewController:customWebView animated:NO];
}
-(IBAction)feedProxyPressed:(id)sender
{
CustomWebView *customWebView = [[CustomWebView alloc] initWithStringURL:@"http://feedproxy.google.com/~r/spaceheadlines/~3/kbL0jv9rbsg/15159-dallas-tornadoes-satellite-image.html"];
[self.navigationController pushViewController:customWebView animated:NO];
}
-(IBAction)cnnPressed:(id)sender
{
CustomWebView *customWebView = [[CustomWebView alloc] initWithStringURL:@"http://www.cnn.com/2012/04/04/us/california-shooting/index.html?eref=rss_mostpopular"];
[self.navigationController pushViewController:customWebView animated:NO];
}
The CustomWebView is just a UIWebView linked in IB to UIWebView Property
@implementation CustomWebView
@synthesize webView, link;
- (id)initWithStringURL:(NSString *) stringURL
{
if (self = [super init]) {
link = stringURL;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:link];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView loadRequest:urlRequest];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
My problem is that I set the heap baseline to be the initial ViewController once everything is loaded. I then check the heap after loading a page then returning to the ViewController and get the following heapshots:
Which shows that after each series of clicking on a button and returning to the ViewController the heap continues to grow even though the CustomWebView should all be released.
EDIT:
The sample project described above can be found on github
I havent used ARC yet, but looking at your custom webview code, I think your webviews that you created are still alive.
if you want to be sure that your webviews are killed properly, make sure that in the viewWill/DidDisappear, call [webview stopLoading], and nil the webview.
(caution: if you are pushing another view, then also the webview will be killd, so make sure to handle those issues well)
Most often, I have had issues with webViews where even after popping the viewController, a call back to some webView delegate method would crash the app. (I guess ARC prevents it from crashing).
Let me know if this helps.
I had the same-ish problem, the i found this little piece of magic
Brendan a couple of points:
You have not posted enough code to be sure of what is happening. But why not have the controller own a SINGLE UIWebView and rather than creating another one on each button press simply pass it a string with the relevant URL? That is a better design pattern that will guarantee that you never have more than one around.
@interface WebViewViewController : UIViewController<UIWebViewDelegate>
UIWebView is a memory pig and doesn't deallocate memory well. I put a -(void) dealloc call in your CustomWebView class and it's called as expected when the Back button is hit.
You can try [[NSURLCache sharedURLCache] removeAllCachedResponses] or use and then free your own copy of NSURLCache, but frankly UIWebView never fully cleans up after itself.
I have been using ARC for a while now and I have found in the past that the web view will hold onto whatever was loaded until its told to load something else. The way I get around this is to use a javascript call in the view will (or Did) dissapear method like so:
This releases the memory for me.