9

我目前正在使用 ARC 在 iOS 5.1 中构建导航控制器应用程序。我经常需要显示网页,我制作了一个 Web 查看器,它只是一个 UIWebView,两侧有一些自定义内容。当用户完成浏览页面时,他们点击返回按钮,该按钮应该释放与自定义 Web 查看器相关的所有内存。我的问题是按下后退按钮时似乎没有释放所有内存。我已经构建了一个玩具应用程序(在 github 上),它只有几个按钮,每个按钮都有一个调用不同页面的第一响应者。

@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];
}

CustomWebView 只是在 IB 中链接到 UIWebView 属性的 UIWebView

@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];
}

我的问题是我将堆基线设置为加载所有内容后的初始 ViewController。然后我在加载页面后检查堆,然后返回 ViewController 并获得以下堆:

快照

这表明在每一系列单击按钮并返回 ViewController 之后,即使应该全部释放 CustomWebView,堆也会继续增长。

编辑:

上面描述的示例项目可以在github上找到

4

6 回答 6

8

我有同样的问题,我发现了这个小魔法

/*

 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];
于 2012-07-17T11:37:32.250 回答
1

UIWebView 是一个内存猪,不能很好地释放内存。我在您的 CustomWebView 类中放置了一个 -(void) dealloc 调用,并在按下 Back 按钮时按预期调用。

您可以尝试 [[NSURLCache sharedURLCache] removeAllCachedResponses] 或使用然后释放您自己的 NSURLCache 副本,但坦率地说,UIWebView永远不会完全清理自身。

于 2012-04-15T13:30:51.483 回答
1

我已经使用 ARC 一段时间了,过去我发现 web 视图会保留加载的任何内容,直到它被告知加载其他内容。我解决这个问题的方法是在视图中使用 javascript 调用将(或 Did)dissapear 方法,如下所示:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self.webView loadHTMLString:@"<html></html>" baseURL:nil];
}

这为我释放了记忆。

于 2012-04-11T20:27:24.497 回答
0

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.

于 2012-04-09T23:01:28.403 回答
0

@interface WebViewViewController : UIViewController<UIWebViewDelegate>

- (void)viewDidLoad
{
[super viewDidLoad];
NSString* urlAddress = @"http://www.google.com";
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
self.webView.delegate = self;
[self.webView loadRequest:requestObj];
}

-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[_webView stopLoading];
[_webView loadHTMLString:@"<html><head></head><body></body></html>" baseURL:nil];
[_webView stopLoading];
[_webView removeFromSuperview];
}

- (void)dealloc
{
[_webView stopLoading];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
[_webView stopLoading];
_webView = nil;
}
于 2014-07-12T17:56:34.150 回答
0

布伦丹几点:

您没有发布足够的代码来确定发生了什么。但是为什么不让控制器拥有一个单一的 UIWebView 而不是在每个按钮按下时创建另一个,只需将一个带有相关 URL 的字符串传递给它呢?这是一种更好的设计模式,可以保证你身边永远不会超过一个。

于 2012-04-11T13:23:00.160 回答