14

after multiple days of banging my head against the wall and having sleepless nights I'm hoping to find some help here. I've gone through various posts here, but none of the answers seem to provide a resolution for me.

In short, my problem is that my App crashes after heavy usage (>10min) of the UIWebView (e.g. opening larger news paper sites in series - one after the other).

To give more details: I am writing an iPhone App and from the MainViewController I push a browserViewController on the navigationController. The browserViewController loads a nib which contains a UWebView (I do not create the WebView programatically). The UIWebView is wired up using Interface Builder.

When going back to Main and then going again to the browserViewController, I only recreate the browserViewController if it is nil. (I want to keep the content that is loaded i the UIWebView - only if there is a memory warning shoud this view be unloaded and release all memory used).

In both, MainViewController and browserViewController I am responding to memory warnings, but this seems not to provide enough relief.

Looking at Instruments I noticed that for example CFData(store) keeps increasing. And even if I simulate a memory warning (see code below) and call viewDidUnload on browserViewController, CFData remains allocated and does not get freed.

So my biggest question is:
How to free up memory created from "browsing"?

This counts for two cases:
- how do I make sure that viewDidUnload properly frees memory allocated my CFData(store)?
- how to free up memory when the user keeps loading pages in browserViewController?
.
Who manages CFData?

See below for my simplified sample code:

MainViewController.h

//  MainViewController.h
#import "myAppDelegate.h"
#import "BrowserViewController.h"

@interface MainViewController : UIViewController {
    BrowserViewController *browViewController;
}

- (void) switchToBrowserViewController;

@end

MainViewController.m

//  MainViewController.m
#import "MainViewController.h"

@implementation MainViewController

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    [browViewController release];
    browViewController = nil;
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)dealloc {
    [browViewController release];
    browViewController = nil;
    [super dealloc];
}

- (void) switchToBrowserViewController {

    // create new browViewController if needed
    if ( browViewController == nil ) {
        browViewController = [[BrowserViewController alloc]     initWithNibName:@"BrowserViewController" bundle:nil];
    }

    browViewController.navigationItem.hidesBackButton = YES;

    [((myAppDelegate *)[UIApplication sharedApplication].delegate).navController setNavigationBarHidden:YES animated:NO];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration: 1];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:
  ((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController.view cache:YES];

    [((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController pushViewController:browViewController animated:NO];
    [UIView commitAnimations];

}

@end

BrowserViewController.h

//  BrowserViewController.h

#import <UIKit/UIKit.h>
#import "myAppDelegate.h"

@interface BrowserViewController : UIViewController <UIWebViewDelegate> {
    IBOutlet UITextField *browserURLField;
    IBOutlet UIWebView *browserWebView;
}

@property (nonatomic, retain) UIWebView *browserWebView;

- (void) loadURLinBrowser;

@end

BrowserViewController.m

//  BrowserViewController.m
#import "BrowserViewController.h"

@implementation BrowserViewController
@synthesize browserWebView;

- (void)viewDidLoad {
    [browserWebView setDelegate:self];
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
}

- (void)viewDidUnload { 
    [super viewDidUnload];

    [browserWebView stopLoading];
    [browserWebView setDelegate:nil];
    [browserWebView removeFromSuperview];
    [browserWebView release];
    browserWebView = nil;

    browserURLField = nil;
}

- (void)dealloc {
    [browserURLField release];

    browserWebView.delegate = nil;
    [browserWebView stopLoading];
    browserWebView = nil;
    [browserWebView release];

    [super dealloc];
}

- (void) switchBackToMainViewController {

    [((myAppDelegate *)[UIApplication sharedApplication].delegate).navController setNavigationBarHidden:NO animated:NO];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration: 1];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController.view cache:YES];

    [((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController popViewControllerAnimated:NO];

    [UIView commitAnimations];
}

- (void) loadURLinBrowser {
    NSURL *url = [[NSURL alloc] initWithString:browserURLField.text];
    NSMutableURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
    [browserWebView loadRequest: request];
    [request release];
    [url release];
}

@end

I have tried various recommendations from other posts. For example:

  • 1) Loading an empty page into the WebView.

        NSString *html = @"<html><head></head><body></body></html>";
        [browserWebView loadHTMLString:html baseURL:nil];
    
  • 2) using removeAllCachedResponses on various places in the above code

        [[NSURLCache sharedURLCache] removeAllCachedResponses];
    
  • 3) setSharedURLCache did also not provide relief ( I also used this in the AppDelegate applicationDidFinishLaunching).

        NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
        [NSURLCache setSharedURLCache:sharedCache];
        [sharedCache release];
    

Unfortunately none of this has helped to "clear the cache" or to free memory allocated by CFData(store).

If anyone could shine some light on this and let me know what I'm missing or doing wrong I would greatly appreciate this.

.
.

Edit:
After the initial reply from KiwiBastard I added a screen shot that shows what I observe in Instruments:

enter image description here

.
.

Edit from June 2010:
I have still not been able to solve this.
In a second attempt, I created the UIWebView completely programmatically.
Still same issue. However I noticed a strange behavior. If I load for example a PDF document into the webView and I do not scroll the PDF page up or down, the webView & data gets successfully released. However as soon as I scroll to the second page, the dealloc won't work any longer and my App ends up running out of memory at some point. This is totally strange and I cannot get this resolved.
Anyone any idea? Help?

4

3 回答 3

2

要释放CFData,您只需调用CFRelease(您的 CFData 对象名称)

于 2011-07-25T12:11:26.167 回答
1

我认为可能发生的情况是您的浏览器永远不会被释放,并且 viewDidUnload 可能永远不会被调用。

因为你的 MainViewController 有一个 BrowserViewController 类型的变量,它永远不会被释放,它会在你的应用程序的生命周期中驻留。此外,由于您只是切换视图,因此视图也将保留在内存中。

我可以建议您在需要时尝试创建 BrowserViewController 变量,并在导航控制器推送它后释放它,例如

 BrowserViewController *browViewController = [[BrowserViewController alloc]     initWithNibName:@"BrowserViewController" bundle:nil];

 browViewController.navigationItem.hidesBackButton = YES;

 [((myAppDelegate *)[UIApplication sharedApplication].delegate).navController setNavigationBarHidden:YES animated:NO];

 [UIView beginAnimations:nil context:NULL];
 [UIView setAnimationDuration: 1];
 [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:
  ((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController.view cache:YES];

 [((myAppAppDelegate *)[UIApplication sharedApplication].delegate).navController pushViewController:browViewController animated:NO];
 [UIView commitAnimations];
 [browViewController release];

我知道它会稍微影响性能,因为它每次都必须加载笔尖,但是您显然不想缓存 vc 吗?

于 2010-10-20T23:16:48.823 回答
1

我在某处读到,这是 UIWebView 的一个众所周知的错误。有人说要使用静态 webview 对象来避免一次又一次地初始化它,但找不到合适的解决方案。即使您遵循相同的方法。幸运的是,我的要求是一个带有图像的普通 Web 视图。所以我最终使用了带有 UIImageView 和 UITextView 的自定义控制器而无需编辑。对我来说很好。

于 2012-02-18T05:24:29.793 回答