Предотвращение выделения памяти UIWebView на неопределенный срок (NSURLCache, по-видимому, не работает)

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

После чтения другое stackoverflow questions и поиск в web, я решил попробовать NSURLCache sharedURLCache, но я не могу понять, как это на самом деле работает.

Мой сценарий тестирования таков:

Я реализовал тестовое приложение для iOS 5, в котором у меня есть одно представление с UIWebView внутри. Этот UiWebview загрузит локальный файл index.html следующим образом:

// Create an NSString from the local HTML file
NSString *fullURL = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"www"];
NSURL *url = [NSURL fileURLWithPath:fullURL];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
// Load local HTML file
[self.webView loadRequest:requestObj];

В этом файле index.html у меня есть сценарий JS, который загружает JSON с Flickr с последними изображениями, загруженными в их общедоступный канал. Каждое изображение добавляется в список. Весь этот процесс повторяется каждую секунду, пока мы не достигнем 1000 изображений, загруженных из канала. Смотрите код:

var nImg = 0;

function getData()
{
    $.getJSON('http://api.flickr.com/services/feeds/photos_public.gne?format=json&jsoncallback=?', function(data)
    {
        var items = [];
        $.each(data.items, function(i, image) {
            items.push('<li id="' + image.title + '"><img src="' + image.media.m + '"/></li>');
        });
        $('#page > #imagesList').append(items.join''));
        nImg += items.length;
    });
    $('#page > #numImages').html(nImg);

    if(nImg < 1000)
        setTimeout("getData();", 1000); // Get more data in 1s
}

$(document).ready(function()
{
    getData();
});

Наконец, в моем AppDelegate я настроил sharedURLCache, как написано в этом сообщении:

// Initialize the Cache, so we can control the amount of memory it utilizes
int cacheSizeMemory = 4*1024*1024; // 4MB
int cacheSizeDisk = 32*1024*1024; // 32MB
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:nil];

[NSURLCache setSharedURLCache:sharedCache];

Но, несмотря на то, что это должно произойти, когда я открываю инструменты и запускаю приложение, проверяющее распределения, память продолжает расти, пока мы загружаем изображения (до 20 МБ), вместо того, чтобы сгладить около 4-6 МБ, как я ожидал бы, если бы UIWebView будет использовать этот sharedURLCache для кеширования загруженных изображений.

Развитие инструментов после того, как мы достигли 1000 изображений

Кто-нибудь знает, что я делаю не так? Я что-то неправильно понял? Я неправильно загружаю страницу? Использует ли UIWebView другой кеш для изображений, загружаемых в JS?

Пожалуйста, поделись своими мыслями. Мне действительно нужно понять, как работает этот sharedURLCache и как UIWebView использует его для кеширования URLRequest, изображений, ... в случае, если он вообще используется. Я не хочу иметь приложение, использующее UIWebView, которое может бесконтрольно выделять память.


person veducm    schedule 07.03.2013    source источник


Ответы (1)


Как у вас все получилось в итоге? Я заметил, что ваш *sharedCache initWithMemoryCapacity имеет diskPath аргумент, равный nil.

Из яблочного доко:

В iOS путь - это имя подкаталога каталога кэша приложения по умолчанию, в котором хранится кеш на диске (подкаталог создается, если он не существует).

Ознакомьтесь с этой ссылкой от Two Bit Labs о том, как использовать кеш: http://twobitlabs.com/2012/01/ios-ipad-iphone-nsurlcache-uiwebview-memory-utilization/

Настройка общего кеша

Во-первых, давайте настроим кеш при запуске приложения (до того, как будут сделаны какие-либо запросы), чтобы мы могли контролировать объем памяти, который оно использует. В вашем UIApplicationDelegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {   
    int cacheSizeMemory = 4*1024*1024; // 4MB
    int cacheSizeDisk = 32*1024*1024; // 32MB
    NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
    [NSURLCache setSharedURLCache:sharedCache];
...

Вышеупомянутое настраивает кеш-память 4 МБ с кеш-памятью диска 32 МБ. Дисковый кеш будет находиться в каталоге кэша iOS по умолчанию в подкаталоге под названием «nsurlcache».

Как реагировать на предупреждения о памяти

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

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
}

Теперь, когда вы запустите свое приложение в профилировщике, вы должны увидеть, что использование памяти выравнивается, а если вы активируете предупреждение памяти в симуляторе, вы должны увидеть падение использования памяти.

person Ann Taylor    schedule 17.10.2013
comment
Спасибо за ответ! Я не понял, в чем проблема, и ссылка, которую вы цитируете, совпадает с той, по которой я на самом деле следовал, чтобы выполнить этот тест (вы можете видеть, что я связал ее в своем вопросе): $ - person veducm; 18.10.2013