5

I'm getting memory leaks that i can't figure out through leaks, build/analyze or overall inspection how to repair. I have a very strong notion that it's due to the loadRequest command from my UIWebview loading javascript, but I can't figure out what's wrong.

Here's my setup:

I have a tabbarcontroller that i programatically create with 4 view controllers: a table view, a mapview, another table view and a webview, respectively.

  • the 1st tableview shows static data.
  • the mapview shows annotations that when clicked populates a variable of the 4th tab, the webview, and switches to the webview to display a locally stored html/javascript file that is a 3d model
  • the 2nd tableview is a listing of all the same information each annotation in the mapview represents, just in table form. it has the same functionality in terms of populating the variable, switching and displaying the html/javascript file in the webview
  • the webview displays the html/javascript file loaded, if not it shows a UIAlertView to select one from the mapview or the list

when i finally get to executing the loadRequest() from the webview, initially everything works fine. however, when i begin to switch between tabs and view different 3d models (i.e. go to the map view click an annotation to show say model x, watch it load in the webview, then switch to the listing table and click a row to show model y (or x too) and watch it load in the webview) i start receiving memory leaks on the ipad, not the simulator. these memory leaks are almost always: General-Block 56, 1024, 8, 244 & 24 and have no responsible frames, libraries or stack traces to follow up with.

in the webview if i comment out the loadrequest line or do a loadrequest with the request object = nil, i have no memory leaks, but when i switch to using a url object that points to the local files (i even tried pointing it to google.com, which has javascript) it erupts in memory leaks.

i've attempted to do each of these:

  • [self.webView loadRequest:nil];
  • [self.webView loadHTMLString:@"" baseURL:nil];
  • [self.webView stopLoading];

in viewWillDisappear of my webViewController in attempt to completely clean out the webview for reuse in the future, but it doesn't seem to be doing much help. i've also attempted doing this prior to doing the loadRequest but i get the same memory leaks.

  • fyi, i'm running the latest xcode 4.0.2 and the ipad has the latest update, 4.3.2
  • from a previous post i commented on and haven't heard back from (general-block memory leak) i believe the problem has to do with the fact that webview doesn't know how to fully rid itself of the javascript when i switch views
  • i did a test with a simple html file with no javascript and the general-block memory leaks are gone. however, i get other cfnetwork / http message memory leaks but that's a different story and not of my concern at the moment.

below is example code of when one of the annotations on the mapView is clicked which triggers the loadModel function in the webViewController:

- (void) mapCallOutPressed: (UIView *) sender {

NSInteger selectedIndex = sender.tag;
MyLocation *selectedObject = [_mapView.annotations objectAtIndex:selectedIndex];

MyModel *model = selectedObject.model;

NSLog(@"Model selected from mapview = %@", model.description);

// Get reference to the webview from the tabBarController (viewController's index=3)
WebViewController *webViewController = [self.tabBarController.viewControllers objectAtIndex:3];
webViewController.model = model;

[webViewController loadModel];

    // Switch tabs to the webView
self.tabBarController.selectedIndex = 3;
[self.tabBarController.selectedViewController viewDidAppear:YES];

below is my webViewController.h & .m:

WebViewController.h:

WebViewController : UIViewController <UIWebViewDelegate> {

UIWebView *webView;
NSString *templateRunFilePath;
MyModel *model;
NSString *templateRunTitle;

@property (nonatomic, retain) UIWebView *webView;
@property (assign) MyModel *model;
@property (nonatomic, copy) NSString *templateRunFilePath;
@property (nonatomic, copy) NSString *templateRunTitle;

-(void) loadModel;

WebViewController.m:

- (void) viewDidLoad {
[super viewDidLoad];
NSLog(@"in webview did load");

self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
self.webView.delegate = self;

self.webView.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
self.webView.scalesPageToFit = YES;

[self.view addSubview:self.webView];

}


- (void) viewWillAppear:(BOOL)animated {

if (self.model) {        
    self.tabBarController.navigationItem.title = [NSString stringWithFormat: @"%@ - %@", self.tabBarController.navigationItem.title, self.model.description];
    
}
else {
    UIAlertView *msg = [[UIAlertView alloc] initWithTitle:@"No Model Selected" 
                                                  message:@"Please select a model from the map or list tab to view." 
                                                 delegate:nil 
                                        cancelButtonTitle:@"OK" 
                                        otherButtonTitles:nil];
    [msg show];
    [msg release];
}
}

- (void) loadModel {
    
NSString *localURLPath = [NSString stringWithFormat:@"%@/%@/%@", self.templateRunFilePath, self.model.folderName, self.model.modelFileName];

NSURL *url = [NSURL fileURLWithPath:localURLPath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL: url];
[self.webView loadRequest:requestObj];
}


- (void)webViewDidFinishLoad:(UIWebView *)webView {   

[[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"WebKitCacheModelPreferenceKey"];
}


-(void)viewWillDisappear:(BOOL)animated {
NSLog(@"webview view will disappear");

[super viewWillDisappear:animated];

//[self.webView loadRequest:nil];
//[self.webView loadHTMLString:@"" baseURL:nil];

 self.webView.delegate = nil;
 }


- (void)dealloc {
    self.webView.delegate = nil;
[self.webView release];

[super dealloc];
}

if you have any advice or corrections, i'd greatly appreciate it. i have < 1 week to figure this out and would highly thank you if you could give me any insight.

thanks!

-Mike

Community
  • 1
  • 1
metral
  • 150
  • 5
  • follow up: when using a local html file that simply loads a very large static image (also stored locally) i get absolutely no memory leaks, as opposed to my original statement regarding me receiving cfnetwork/http errors. i've apparently changed something from when i last observed it that has ceased those leaks. but when i switch to load the object that points to my html which contains javascript (the 3d models) the leaks come back. so uiwebview is definitely struggling to finish computing the javascript or something is being dragged around that doesn't fully cease the javascript operations – metral Apr 21 '11 at 16:11
  • just so you have an idea of what i'm up against, for every ~10 html/javascript 3d model's I display in the webView, it generates approximately 15-20 leaks and once a couple exist, well it's pretty close to exponential from there on – metral Apr 21 '11 at 16:11
  • in an attempt at trying something different, i clear the webview object right before i call loadModel: basically, i nil the webview's delegate, release webview, nil it and execute the code from my viewDidLoad. this seems to not cause leaks but i only manage to load about 2-3 webviews before i get memory warnings and my app crashes. – metral Apr 22 '11 at 05:33
  • it seems that the only leaks im getting now are tons of the general-block 56, a couple 288 and one or two 1024. what exactly changed I couldn't tell you, but its now restricted to those 3 kinds it seems – metral Apr 23 '11 at 16:29

1 Answers1

0

Mike, I am not sure whether you are doing following intentionally or by mistake?

- (void) loadModel {

[self.webView loadHTMLString:@"" baseURL:nil]; // here you are loading... or you have tried with commenting it also?

NSString *localURLPath = [NSString stringWithFormat:@"%@/%@/%@", self.templateRunFilePath, self.model.folderName, self.model.modelFileName];

NSURL *url = [NSURL fileURLWithPath:localURLPath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL: url];
[self.webView loadRequest:requestObj];   // again here you are also loading?
} 
Ravin
  • 8,544
  • 3
  • 20
  • 19
  • please see the comments after the load... message call. – Ravin Apr 21 '11 at 05:19
  • thanks for the quick response Ravin, that was actually something I was trying out at the time but it didnt work, it was intentional. the `[self.webView loadHTMLString:@"" baseURL:nil]` has since been removed – metral Apr 21 '11 at 16:09