Утечка NSURLConnection?

Я настроил nsurl, который собирает данные из http. когда я запускаю инструмент, он говорит, что у меня есть объект NSFNetwork утечки.

и как отпустить theConnection в (void) ButtonClicked? или он выйдет позже?

- (void)ButtonClicked {
    NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:KmlUrl]
                                                cachePolicy:NSURLRequestUseProtocolCachePolicy
                                            timeoutInterval:20.0f];

    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
    if (theConnection) {
        // receivedData is declared as a method instance elsewhere
        NSMutableData *receivedData = [[NSMutableData data] retain];
        [self setKMLdata:receivedData];
    } else {
        // inform the user that the download could not be made
    }
}


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // append the new data to the receivedData
    // receivedData is declared as a method instance elsewhere
    [KMLdata appendData:data];
    NSLog(@"didReceiveData");
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // release the connection, and the data object
    [connection release];
    [KMLdata release];
}


- (void)connection:(NSURLConnection *)connection  didFailWithError:(NSError *)error
{
    // release the connection, and the data object
    [connection release];
    // receivedData is declared as a method instance elsewhere
    [KMLdata release];

}

person vicky    schedule 28.08.2009    source источник


Ответы (4)


Я наконец нашел на это ответ.

Ошибка в приведенном выше коде (который, кстати, является почти точным образцом из SDK docs) отсутствует в коде управления памятью. Автовыпуск - это один вариант, ручной выпуск - другой. Независимо от того, как вы обрабатываете свой объект NSURLConnection, вы получаете утечки с помощью NSURLConnection.

Во-первых, вот решение. Просто скопируйте эти 3 строки кода прямо в connectionDidFinishLoading, didFailWithError и в любое другое место, где вы выпускаете объект NSURLConnection.

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

Кредит mpramodjain на http://forums.macrumors.com/showthread.php?t=573253 для кода.

Проблема вроде бы в следующем - SDK кэширует запросы и ответы на iPhone. Даже кажется, если ваш NSMutableURLRequest cachePolicy настроен так, чтобы не загружать ответ из кеша.

Глупо то, что по умолчанию он, кажется, кеширует много данных. Я передаю много данных (разделенных на несколько соединений) и начал получать предупреждения о памяти, и, наконец, мое приложение умерло.

Необходимые нам документы находятся в NSURLCache (не NSURLConnection), в них говорится:

NSURLCache реализует кэширование ответов на запросы загрузки URL-адресов путем сопоставления объектов NSURLRequest с объектами NSCachedURLResponse. Он представляет собой смесь кэша в памяти и на диске.

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

Эти три строки полностью уничтожают кеш. После добавления их в мое приложение (журнал GPS) количество моих #living объектов остается стабильным.

person William Denniss    schedule 09.12.2009
comment
для записи, я переключился на автозапуск [NSURLConnection connectionWithRequest: request delegate: self], но я не думаю, что это должно иметь значение. - person William Denniss; 09.12.2009
comment
Если ваше приложение выполняет какие-либо другие запросы NSURLRequests, которые должны использовать кеширование, это решение отключит их. Лучшим решением в этом случае может быть реализация кэшированного делегата ответа (который имеет тот же эффект): -(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { return nil; } - person Rob Rix; 14.03.2012
comment
Немного дальше о том, что на самом деле происходит: NSURLCache кэширует ответ на запрос, но использует запрос в качестве ключа. Таким образом, он будет удерживать запрос до тех пор, пока ответы будут кэшироваться. 0-байтовый кеш устраняет это за счет того, что все запросы, сделанные приложением, не кэшируются; реализация метода делегата - это более индивидуальный подход. Недостаточно настроить политику кеширования запроса на игнорирование кеша. - person Rob Rix; 14.03.2012
comment
Если вы не хотите полностью отключать кеширование и не можете или не хотите использовать асинхронное соединение с делегатом, вы можете вызвать [[NSURLCache sharedURLCache] removeCachedResponseForRequest:request]; сразу после отправки запроса. - person David; 26.12.2012
comment
Я использую + [NSURLConnection sendAsynchronousRequest: queue: ЗавершениеHandler:] и + [NSURLConnection sendSynchronousRequest: returnResponse: error] вместе с вашим методом настройки кеша, однако живые байты продолжают увеличиваться, и в конечном итоге мое приложение завершается через ›30 МБ. только этот метод. Есть ли у вас какие-либо идеи? для sendSynchronousRequest я делаю это внутри dispatch_async с SERIAL_QUEUE. Спасибо! - person Zennichimaro; 22.01.2013

Здравствуйте, вы тестировали этот метод делегата?

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
    return nil;
}

Точнее можно управлять кешем.

"reset" NSURLCache * sharedCache может вызвать проблемы в другой части вашего кода?

person Pixman    schedule 24.07.2011

Это частый вопрос, и он решается с помощью магии [автозапуска объекта]. В вашем коде это будет следующим образом:

NSURLConnection *theConnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self] autorelease];

Таким образом, объект автоматически добавляется в «пул автозапуска» и освобождается в начале следующего цикла выполнения после того, как на него больше не ссылаются.

надеюсь, это поможет

Изменить: Кроме того, я не понимаю, почему вам нужно вызывать -retain для вашей переменной ReceiveData.

person h4xxr    schedule 28.08.2009
comment
Хотя вызов autorelease будет работать, он не сработает в тех случаях, когда делегат освобождается до того, как соединение будет освобождено. Лучшим способом было бы назначить соединение переменной экземпляра и отпустить + nil, когда он не нужен. Если ivar соединения все еще назначается, когда объект освобождается, делегат должен быть установлен в ноль перед освобождением соединения. - person rpetrich; 28.08.2009
comment
@rpetrich Я согласен, что ваше предложение более исчерпывающее, однако было ясно, что его вопрос показал основное непонимание управления памятью на iPhone, и поэтому я хотел дать ему концептуально более простое решение - person h4xxr; 28.08.2009
comment
@rpetrich, не могли бы вы привести пример кода. Я пытался решить эту проблему разными способами, но до сих пор есть утечка. - person Jordan; 29.08.2009
comment
@rpetrich, да, я бы тоже хотел увидеть твой пример. - person vicky; 31.08.2009

Я использую статический метод / подход с автоматическим выпуском, и, похоже, он работает нормально:

[NSURLConnection connectionWithRequest:theRequest delegate:self];

Таким образом, вам даже не нужно беспокоиться об освобождении в обратных вызовах делегата. Оказывается, что счетчик удержания соединения на самом деле равен 2 (а не 1) после того, как он был выделен в приведенных выше примерах, что меняет мое представление об этой «утечке» памяти.

@rpetrich Я вообще-то не думаю, что вам нужно беспокоиться об освобождении делегата до того, как будет освобождено соединение. Соединение сохраняет своего делегата, а само соединение фактически сохраняется какой-то очередью открытых соединений. Я написал в своем блоге сообщение о своих экспериментах с NSURLConnection:

«Возможная утечка объекта» с NSURLConnection

person Alex Medearis    schedule 07.01.2012