UIWebView - 何时(或如何)发布CFData?

时间:2023-01-04 09:44:35

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).

简而言之,我的问题是我的应用程序在UIWebView大量使用(> 10分钟)后崩溃(例如,逐个打开更大的新闻纸网站 - 一个接一个)。

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.

为了提供更多细节:我正在编写一个iPhone应用程序,并从MainViewController我在navigationController上推送一个browserViewController。 browserViewController加载一个包含UWebView的笔尖(我不以编程方式创建WebView)。 UIWebView使用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).

当回到Main然后再次访问browserViewController时,我只重新创建browserViewController(如果它是nil)。 (我想保留在UIWebView中加载的内容 - 只有在存在内存警告时才会卸载此视图并释放所有使用的内存)。

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

在MainViewController和browserViewController中我都在响应内存警告,但这似乎没有提供足够的缓解。

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.

看看仪器我注意到例如CFData(商店)不断增加。即使我模拟内存警告(请参阅下面的代码)并在browserViewController上调用viewDidUnload,CFData仍然会被分配并且不会被释放。

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?

这有两种情况: - 如何确保viewDidUnload正确释放分配给我的CFData(存储)的内存? - 当用户继续在browserViewController中加载页面时如何释放内存? 。谁管理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.

    1)将空白页面加载到WebView中。

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

    2)在上面代码中的各个地方使用removeAllCachedResponses

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

    3)setSharedURLCache也没有提供缓解(我也在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).

不幸的是,这些都没有帮助“清除缓存”或释放由CFData(商店)分配的内存。

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:

编辑:在KiwiBastard的初步回复后,我添加了一个屏幕截图,显示我在仪器中观察到的内容:

UIWebView  - 何时(或如何)发布CFData?

.
.

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?

从2010年6月开始编辑:我仍然无法解决这个问题。在第二次尝试中,我完全以编程方式创建了UIWebView。还是同样的问题。但是我发现了一种奇怪的行为。如果我将例如PDF文档加载到webView中并且我不向上或向下滚动PDF页面,则会成功释放webView和数据。但是,当我滚动到第二页时,dealloc将不再工作,我的应用程序最终会在某些时候耗尽内存。这很奇怪,我无法解决这个问题。谁有任何想法?帮帮我?

3 个解决方案

#1


2  

To release CFData you only need to call CFRelease(your CFData object name).

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

#2


1  

I think what could be happening is that your Browser is never deallocated, and the viewDidUnload is probably never being called.

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

Because your MainViewController has a variable of type BrowserViewController that is never released, that will be resident for the life of your app. Also because you are only switching views, the view will stay in memory too.

因为您的MainViewController有一个从未发布过的BrowserViewController类型的变量,所以它将在您的应用程序的生命周期内驻留。另外,因为您只是切换视图,视图也将保留在内存中。

Can I suggest you try creating the BrowserViewController variable when you need it, and release it once it has been pushed by the navcontroller eg

我是否可以建议您在需要时尝试创建BrowserViewController变量,并在navcontroller推送后释放它,例如

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

I know that it will slightly effect performance because it has to load the nib everytime, but you distinctly don't want to cache the vc anyway?

我知道它会稍微影响性能,因为它必须每次加载nib,但你明显不想缓存vc吗?

#3


1  

Somewhere I read, this is a well known bug with UIWebView. Some says to use a static webview object to avoid initializing it again and again but couldn't find a proper solution. Even you follows the same approach. Luckily my requirement was a plain web view with an image. So I ended up using a custom controller with a UIImageView and a UITextView without editing. Works fine for me.

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

#1


2  

To release CFData you only need to call CFRelease(your CFData object name).

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

#2


1  

I think what could be happening is that your Browser is never deallocated, and the viewDidUnload is probably never being called.

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

Because your MainViewController has a variable of type BrowserViewController that is never released, that will be resident for the life of your app. Also because you are only switching views, the view will stay in memory too.

因为您的MainViewController有一个从未发布过的BrowserViewController类型的变量,所以它将在您的应用程序的生命周期内驻留。另外,因为您只是切换视图,视图也将保留在内存中。

Can I suggest you try creating the BrowserViewController variable when you need it, and release it once it has been pushed by the navcontroller eg

我是否可以建议您在需要时尝试创建BrowserViewController变量,并在navcontroller推送后释放它,例如

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

I know that it will slightly effect performance because it has to load the nib everytime, but you distinctly don't want to cache the vc anyway?

我知道它会稍微影响性能,因为它必须每次加载nib,但你明显不想缓存vc吗?

#3


1  

Somewhere I read, this is a well known bug with UIWebView. Some says to use a static webview object to avoid initializing it again and again but couldn't find a proper solution. Even you follows the same approach. Luckily my requirement was a plain web view with an image. So I ended up using a custom controller with a UIImageView and a UITextView without editing. Works fine for me.

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