9

Ustawiłem nsurl, który pobiera dane z http. po uruchomieniu instrumentu, mówi, że mam przeciek obiektu NSFNetwork.NSURLConnection leak?

i jak mogę zwolnić przycisk theConnection w (void) ButtonClicked? czy będzie później wydany?

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

} 

Odpowiedz

2

Jest to częste pytanie, które rozwiązuje magia [autorelease obiektów]. W kodzie byłoby to w następujący sposób:

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

W ten sposób obiekt jest automatycznie dodawany do „puli” i autorelease dealloc'd na początku następnej pętli biegu po to już nie jest wymieniony.

nadzieję, że pomoże

Edycja: Również nie widzę dlaczego jesteś konieczności zadzwonić -retain o zmiennej receivedData.

+0

Podczas rozmowy autorelease będzie działać, to nie w przypadkach, gdy pełnomocnik jest uwalniane, zanim połączenie zostanie zwolniony. Lepszym sposobem byłoby przypisanie połączenia do zmiennej instancji i zwolnienie + nil go, gdy nie jest potrzebne. Jeśli połączenie ivar jest nadal przypisane, gdy obiekt deallocs, delegat musi być ustawiony na zero przed zwolnieniem połączenia. – rpetrich

+0

@rpetrich Zgadzam się, że Twoja sugestia jest bardziej wyczerpująca, ale było jasne, że jego pytanie wykazało podstawowe nieporozumienie dotyczące zarządzania pamięcią na iPhonie i dlatego chciałem dać mu koncepcyjnie łatwiejsze rozwiązanie – h4xxr

+0

@rpetrich, czy możesz podać przykład kodu. Próbowałem rozwiązać ten problem na wiele sposobów i nadal mam wyciek. – Jordan

17

W końcu znalazłem odpowiedź na to.

Błąd w powyższym kodzie (który swoją drogą jest prawie dokładną próbką z SDK docs) nie znajduje się w kodzie zarządzania pamięcią. Autorelease jest jedną z opcji, ręczne wydanie to kolejna. Bez względu na to, jak obchodzisz się z obiektem NSURLConnection, dostajesz przecieki za pomocą NSURLConnection.

Po pierwsze, oto rozwiązanie. Po prostu skopiuj te 3 linie kodu bezpośrednio do connectionDidFinishLoading, didFailWithError i gdziekolwiek indziej zwolnisz obiekt NSURLConnection.

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

zgłosił mpramodjain na http://forums.macrumors.com/showthread.php?t=573253 do kodu.

Problem wydaje się taki - pakiet SDK buforuje żądania i odpowiedzi na telefonie iPhone. Nawet wydaje się, że twoja NSMutableURLRequest cachePolicy jest ustawiona tak, aby nie ładowała odpowiedzi z pamięci podręcznej.

Głupie jest to, że domyślnie buforuje dużo danych. Wysyłam dużo danych (podzielonych na wiele połączeń) i zacząłem otrzymywać ostrzeżenia z pamięci, a na końcu moja aplikacja zginęła.

Docs musimy są w NSURLCache (nie NSURLConnection), stwierdzają:

NSURLCache realizuje buforowanie odpowiedzi na żądania obciążenia URL przez mapowania NSURLRequest sprzeciwia się NSCachedURLResponse obiektów. Jest to kompilacja pamięci podręcznej w pamięci i pamięci podręcznej na dysku.

dostarczone są sposoby manipulowania rozmiary każdego z tych pamięci podręcznej oraz aby kontrolować drogę na dysku użyć do stałej pamięci podręcznej danych.

Te trzy linie powodują całkowite wymazanie pamięci podręcznej. Po dodaniu ich do mojej aplikacji (GPS Log) moja liczba obiektów #living pozostaje stała.

+0

dla rekordu, przełączyłem się na autorelease'd [NSURLConnection connectionWithRequest: request delegate: self], ale nie sądzę, że powinno to mieć znaczenie. –

+0

Jeśli twoja aplikacja wykonuje inne żądania NSURLR, że _niekorzystać z buforowania, to rozwiązanie je wyłączy. Lepszym rozwiązaniem w tym przypadku może być realizacji buforowanego pełnomocnik reakcji (która ma to samo): '- (NSCachedURLResponse *) połączenie: (NSURLConnection *) willCacheResponse połączenia (NSCachedURLResponse *) zero cachedResponse { \t powrotu; } ' –

+1

Nieco dalej na temat tego, co się faktycznie dzieje: NSURLCache buforuje odpowiedź na żądanie, ale używa żądania jako klucza. W ten sposób będzie trzymać się żądania tak długo, jak odpowiedzi będą buforowane. Pamięć podręczna o wielkości 0 bajtów pokonuje to, kosztem usunięcia wszystkich żądań aplikacji z pamięci podręcznej; wdrożenie metody delegatów to bardziej dostosowane podejście. Ustawienie zasad pamięci podręcznej żądania w celu zignorowania pamięci podręcznej nie jest wystarczające. –

5

Witam, czy przetestowałeś tę metodę delegowania?

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

Możesz precyzyjniej zarządzać pamięcią podręczną.

"reset" NSURLCache * sharedCache może powodować problemy w innych częściach kodu?

1

Używam metody statycznej/autoreleased podejścia i wydaje się działać prawidłowo:

[NSURLConnection connectionWithRequest:theRequest delegate:self]; 

ten sposób nawet nie trzeba się martwić o zwolnieniu w callbacków delegata. Okazuje się, że liczba zatrzymań połączenia wynosi w rzeczywistości 2 (nie 1) po przydzieleniu w powyższych przykładach, co zmienia sposób, w jaki myślałem o tym wycieku pamięci.

@rpetrich Nie sądzę, że powinieneś się martwić, że delegat zostanie zwolniony, zanim połączenie zostanie zwolnione. Połączenie zachowuje delegata, a samo połączenie jest faktycznie zachowywane przez jakąś kolejkę otwartych połączeń. Pisałem na blogu o moich doświadczeniach z NSURLConnection na moim blogu:

"Potential leak of object" with NSURLConnection