Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIWebView not stopping immediately

I have tried all these (one, two, three, four) solutions, but after I come back from web view screen to previous viewController, it freezes for around 2 seconds(sometimes more). There is nothing in viewWillAppear which will cause the freezing.

Here is viewWillDisappear of web view controller :

-(void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [detailWebView stopLoading];
    detailWebView.delegate = nil;
    NSLog(@"viewWillDisappear called !!!");
}

First viewController :

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.navigationController.navigationBar setBarTintColor:[UIColor colorWithRed:41.0/255.0 green:151.0/255.0 blue:132.0/255.0 alpha:1.0]];
    UIImage *imagePlus = [[UIImage imageNamed:@"create.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    buttonCreate = [UIButton buttonWithType:UIButtonTypeCustom];
    [buttonCreate setImage:imagePlus forState:UIControlStateNormal];
    [buttonCreate addTarget:self action:@selector(createActivity:) forControlEvents:UIControlEventTouchUpInside];
    buttonCreate.frame = CGRectMake(self.view.frame.size.width - 40, 10, 16, 16);
    [self.navigationController.navigationBar addSubview:buttonCreate];
    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"back", nil) style:UIBarButtonItemStylePlain target:nil action:nil];
    [backButton setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]} forState:UIControlStateNormal];
    self.navigationItem.backBarButtonItem = backButton;
    [self.navigationController.navigationBar setTintColor:[UIColor blackColor]];
}

Update : I just confirmed that if I let the webView load completely and then go to previous viewController, there is no freeze observed.

like image 980
Nitish Avatar asked Jul 20 '15 10:07

Nitish


4 Answers

I think the webview might still process in the background. And I made the experience that it is quite annoying to release a UIWebView completely. You might want to have a look in the Profiler: up and close the webview's ViewController several times, the buffer should steadily increase.

This is why I came up to merge several solution approaches from stack overflow to finally and completely remove all storage from a webview and also stop it from running.

It is crucial, that the webview is set to be nil, to really deallocate it's memory, in former days we had the release method, which is now "obsolete" if you make use of the ARC properly.

- (void)releaseWebView:(UIWebView *)webView
{
    /*

     There are several theories and rumors about UIWebView memory leaks, and how
     to properly handle cleaning a UIWebView instance up before deallocation. This
     method implements several of those recommendations.

     #1: Various developers believe UIWebView may not properly throw away child
     objects & views without forcing the UIWebView to load empty content before
     dealloc.

     Source: http://stackoverflow.com/questions/648396/does-uiwebview-leak-memory

     */
    [webView loadHTMLString:@"" baseURL:nil];

    /*

     #2: Others claim that UIWebView's will leak if they are loading content
     during dealloc.

     Source: http://stackoverflow.com/questions/6124020/uiwebview-leaking

     */
    [webView stopLoading];

    /*

     #3: Apple recommends setting the delegate to nil before deallocation:
     "Important: Before releasing an instance of UIWebView for which you have set
     a delegate, you must first set the UIWebView delegate property to nil before
     disposing of the UIWebView instance. This can be done, for example, in the
     dealloc method where you dispose of the UIWebView."

     Source: UIWebViewDelegate class reference

     */
    [webView setDelegate:nil];


    /*

     #4: If you're creating multiple child views for any given view, and you're
     trying to deallocate an old child, that child is pointed to by the parent
     view, and won't actually deallocate until that parent view dissapears. This
     call below ensures that you are not creating many child views that will hang
     around until the parent view is deallocated.
     */

    [webView removeFromSuperview];

    webView = nil;
}

Please give it a try and call this method in viewWillDisappear:

like image 155
Lepidopteron Avatar answered Nov 03 '22 23:11

Lepidopteron


Try this in viewWillDisappear:

-(void)viewWillDisappear:(BOOL)animated {  
  [detailWebView setDelegate:nil];
  [detailWebView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString:@""]]];
  [detailWebView stopLoading];
  [super viewWillDisappear:animated];
}
like image 44
Mrunal Avatar answered Nov 03 '22 23:11

Mrunal


I do the following, which is similar to what @Mrunal suggests but loads a valid page. I originally added this to deal with a situation where a loaded page had timers which continued to run forever after popping back from a UIWebView. For me this works well.

- (void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    // Load a blank page as found things hang around.
    [self.theWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
}

NB I do not call stopLoading as that stops the load request. This could be what is wrong with Mrunal's solution?

like image 45
Rory McKinnel Avatar answered Nov 04 '22 00:11

Rory McKinnel


Are you using NSURLProtocol to intercept the web requests from your UIWebView? The below answer is written on that assumption.

Loading of the web page involves sending out requests for multiple resources ( images, videos, html, javascript). Each of those resources have an URL that will be intercepted by the NSURLProtocol

Now if you close the webView before all the resources are loaded, NSURLProtocol takes sometimes to cancel all the open requests for resources it is intercepting and in this process freezing your app.

You will unregister from NSURLProtocol before you exit out of webView. So

 override func viewWillDisappear{
   NSURLProtocol.unregisterClass(/*your custom url protocol class name here*/)
  }

should fix the freezing issue

PS: Sometimes you might have NSURLProtocol defined for the entire app, in which case I think it is better to separate out the NSURLProtocol for UIwebView from the rest of app. I don't know much about your project for me to comment if this is a feasible option for you

like image 3
shrutim Avatar answered Nov 04 '22 00:11

shrutim