UIWebView - Когда (или как) CFData освобождается?

после нескольких дней ударов головой о стену и бессонных ночей я надеюсь найти здесь какую-то помощь. Здесь я прочитал различные сообщения, но ни один из ответов, похоже, не дает мне разрешения.

Вкратце, моя проблема заключается в том, что мое приложение падает после интенсивного использования ( > 10 минут) UIWebView (например, открывая новые сайты для газетных статей последовательно - один за другим).

Чтобы предоставить более подробную информацию: Я пишу приложение для iPhone, а из MainViewController я нажимаю на browserViewController на navigationController. BrowsViewController загружает наконечник, который содержит UWebView (я не создаю WebView программно). UIWebView подключен с помощью Interface Builder.

Возвращаясь к Main, а затем снова перейдя в браузер BrowsController, я только создаю браузер BrowsController, если он равен нулю. (Я хочу сохранить загруженный контент я UIWebView - только если есть предупреждение о сохранении памяти, это представление будет выгружено и выпустить всю используемую память).

В обоих, MainViewController и browserViewController я отвечаю на предупреждения о памяти, но это, похоже, не дает достаточного облегчения.

Глядя на инструменты, я заметил, что, например, CFData (store) продолжает расти. И даже если я смоделирую предупреждение о памяти (см. Код ниже) и вызываю viewDidUnload на browserViewController, CFData остается выделенным и не освобождается.

Итак, мой самый большой вопрос:
Как освободить память из "просмотра"?

Это считается для двух случаев:
- как я могу убедиться, что viewDidUnload правильно освобождает память, выделенную мои CFData (хранилище)?
- как освободить память, когда пользователь продолжает загружать страницы в 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) Загрузка пустой страницы в WebView.

        NSString *html = @"<html><head></head><body></body></html>";
        [browserWebView loadHTMLString:html baseURL:nil];
    
  • 2), используя removeAllCachedResponses в разных местах в приведенном выше коде

        [[NSURLCache sharedURLCache] removeAllCachedResponses];
    
  • 3) setSharedURLCache также не обеспечил облегчение (я также использовал это в приложении AppDelegate applicationDidFinishLaunching).

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

К сожалению, ничто из этого не помогло "очистить кеш" или освободить память, выделенную CFData (store).

Если бы кто-нибудь мог осветить этот свет и сообщить мне, что я пропущу или что-то не так, я бы очень признателен этому.

.
,

Edit:
После первоначального ответа от KiwiBastard я добавил снимок экрана, который показывает, что я наблюдаю в Инструменты:

enter image description here

.
,

Изменить с июня 2010 года:
Я все еще не смог это решить.
Во второй попытке я создал UIWebView полностью программно.
Еще одна проблема. Однако я заметил странное поведение. Если я загружаю, например, документ PDF в webView, и я не прокручиваю страницу PDF вверх или вниз, веб-просмотр и данные будут успешно выпущены. Однако, как только я перейду на вторую страницу, dealloc больше не будет работать, и у моего приложения в какой-то момент закончится нехватка памяти. Это совершенно странно, и я не могу решить эту проблему. Любая идея? Помогите?

Ответы

Ответ 1

Чтобы освободить CFData​​strong > , вам нужно только позвонить CFRelease (имя объекта CFData).

Ответ 2

Я думаю, что может произойти то, что ваш браузер никогда не освобождается, и 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];

Я знаю, что это слегка повлияет на производительность, потому что каждый раз нужно загружать nib, но вы явно не хотите кэшировать vc в любом случае?

Ответ 3

Где-то я читал, это хорошо известная ошибка с UIWebView. Некоторые говорят, что использовать статический объект webview, чтобы не инициализировать его снова и снова, но не смогли найти правильное решение. Даже вы придерживаетесь такого же подхода. К счастью, моим требованием был простой веб-просмотр с изображением. Поэтому я закончил использование пользовательского контроллера с UIImageView и UITextView без редактирования. Прекрасно работает для меня.