经过多天的头疼和失眠,我希望在这里找到一些帮助。我已经浏览了这里的各种帖子,但是没有一个答案似乎能为我提供解决方案。
简而言之,我的问题是,当UIWebView被频繁使用(例如连续打开较大的新闻网站)后,我的应用程序会崩溃。
为了提供更多细节: 我正在编写一个iPhone应用程序,从MainViewController中推送browserViewController到导航控制器上。browserViewController加载一个包含UWebView的nib文件(我不是通过编程方式创建WebView)。UIWebView使用Interface Builder进行连接。
当返回到Main并再次转到browserViewController时,仅在其为nil时才重新创建browserViewController。(我想保留已加载的UIWebView内容 - 仅当出现内存警告时,此视图应该被卸载并释放所有使用的内存)。
在MainViewController和browserViewController中,我都会响应内存警告,但这似乎并不能提供足够的缓解。
查看Instruments,我注意到例如CFData(store)不断增加。即使我模拟内存警告(见下面的代码)并在browserViewController上调用viewDidUnload,CFData仍然被分配,并且不会被释放。
所以我最大的问题是:
如何释放从“浏览”中创建的内存?
这适用于两种情况:
- 如何确保viewDidUnload正确释放由CFData(store)分配的内存?
- 当用户在browserViewController中继续加载页面时,如何释放内存?
.
谁管理CFData?
请参见下面的简化样本代码:
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
我尝试了其他帖子中提到的各种建议,比如:
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];
很遗憾,这些都没有帮助“清除缓存”或释放由CFData(store)分配的内存。
如果有人能为此提供一些指导,并让我知道我错过了什么或做错了什么,我将不胜感激。
.
.
编辑:
在KiwiBastard的初始回复之后,我添加了一个屏幕截图,显示我在Instruments中观察到的情况:
.
.
2010年6月的编辑:
我仍然无法解决这个问题。
在第二次尝试中,我完全以编程方式创建了UIWebView。
仍然存在同样的问题。但是我注意到了奇怪的行为。如果我将PDF文档加载到webView中,并且不滚动PDF页面,webView和数据将被成功释放。但是,一旦我滚动到第二页,dealloc就不再起作用,我的应用程序最终会在某个时候耗尽内存。这是非常奇怪的,我无法解决这个问题。
有人有任何想法吗?帮帮忙?
NSMutableURLRequest
而不是只用NSURLRequest
?[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]
吗?browViewController
推送后释放并置空,以查看是否有任何影响。