Czy można zapobiec buforowaniu danych przez NSURLRequest lub usunąć dane z pamięci podręcznej po żądaniu?

90

Na iPhonie wykonuję żądanie HTTP przy użyciu NSURLRequest dla fragmentu danych. Alokacja obiektów gwałtownie rośnie i odpowiednio przypisuję dane. Kiedy skończę z danymi, odpowiednio je zwalniam - jednak instrumenty nie pokazują żadnych danych, które zostały zwolnione!

Moja teoria jest taka, że ​​domyślnie żądania HTTP są buforowane - nie chcę, aby moja aplikacja na iPhone'a buforowała te dane.

Czy istnieje sposób na wyczyszczenie tej pamięci podręcznej po żądaniu lub zapobieżenie buforowaniu jakichkolwiek danych?

Próbowałem użyć wszystkich zasad pamięci podręcznej udokumentowanych trochę jak poniżej:

NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
theRequest.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;

ale wydaje się, że nic nie zwalnia pamięci!

Nick Cartwright
źródło
Czy byłoby możliwe, że nie jest to związane z pamięcią podręczną? Czy próbowałeś sprawdzić dane, aby sprawdzić, czy dane, które powinny zostać ponownie załadowane, są w rzeczywistości stare? Może twój por pochodzi skądinąd. Jak zainicjować i zwolnić NSURLRequests? To może być pomocne w zdiagnozowaniu problemu.
lpfavreau
FYI - Jeśli chcesz usunąć pliki siłą, przykładowy kod, który to zrobisz, jest tutaj: salesforce.stackexchange.com/a/69736
zekel

Odpowiedzi:

158

Zwykle łatwiej jest utworzyć takie żądanie

NSURLRequest *request = [NSURLRequest requestWithURL:url
      cachePolicy:NSURLRequestReloadIgnoringCacheData
      timeoutInterval:60.0];

Następnie utwórz połączenie

NSURLConnection *conn = [NSURLConnection connectionWithRequest:request
       delegate:self];

i zaimplementuj połączenie: willCacheResponse: metoda na delegacie. Zwrócenie zera powinno to zrobić.

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
  return nil;
}
tcurdt
źródło
Bardzo dziękuję za pomoc! Nacięcie.
Nick Cartwright
1
Dzięki za ten pomysł - wielokrotnie dzwoniłem do takiej usługi sieciowej SOAP, która w niekontrolowany sposób rosła, mimo że przecieki nie wskazywały, że coś jest nie tak. Zoptymalizowałem przez kilka dni i ostatecznie próbowałem zapobiec buforowaniu, ponieważ wiele obiektów CFURL * z wewnętrznej struktury kręciło się w pobliżu. Zwrócenie zera z willCacheResponse było jedyną rzeczą, która zadziałała!
Bron Davies,
15
Dlaczego konieczne jest zrobienie obu NSURLRequestReloadIgnoringCacheData i wdrożenie connection:willCacheResponse:?
fabb
1
Cześć, czy to możliwe, że mogę tego użyć do ładowania zawartości lokalnej? Powyższe dotyczy NSUrlConnection, ale ładuję lokalne dane HTML do UIWebView przy użyciu NSUrlRequest. Muszę odrzucić wszelkie buforowanie, ponieważ do widoku internetowego przechodzą obrazy z SQLite, a pamięć rośnie wraz z każdym ładowaniem strony. Dzięki.
jim
7
@fabb, przesłanianie connection:willCacheResponse:pozwala nie przechowywać odpowiedzi w pamięci podręcznej. NSURLRequestReloadIgnoringCacheDataokreśla, że ​​połączenie powinno ładować żądanie bez sprawdzania pamięci podręcznej. Przypuszczalnie ta pierwsza pomaga zarządzać alokacją pamięci.
Christopher Pickslay
12

Mam ten sam problem w mojej aplikacji, gdy poprosiłem o informacje z Twittera. W moim przypadku nie musiałem zachowywać tych poświadczeń, więc po prostu kasuję je za pomocą następnego kodu:

- (void) eraseCredentials{
NSURLCredentialStorage *credentialsStorage = [NSURLCredentialStorage sharedCredentialStorage];
NSDictionary *allCredentials = [credentialsStorage allCredentials];

//iterate through all credentials to find the twitter host
for (NSURLProtectionSpace *protectionSpace in allCredentials)
    if ([[protectionSpace host] isEqualToString:@"twitter.com"]){
        //to get the twitter's credentials
        NSDictionary *credentials = [credentialsStorage credentialsForProtectionSpace:protectionSpace];
        //iterate through twitter's credentials, and erase them all
        for (NSString *credentialKey in credentials)
            [credentialsStorage removeCredential:[credentials objectForKey:credentialKey] forProtectionSpace:protectionSpace];
    }
}

Mam nadzieję, że u kogoś to zadziała :)


źródło
to było idealne rozwiązanie mojego problemu, miałem problem z ponownym logowaniem, ponieważ poświadczenia były przechowywane i były automatycznie przesyłane przez NSURLConnection, wielkie dzięki, to mi bardzo pomogło :)
RVN
Dzięki, to dla mnie praca, naprawdę doceniam twoją sugestię. Właściwie moim problemem jest to, że NSURLRequest przechowuje nazwę użytkownika i hasło. Więc to pomogło w usunięciu danych logowania użytkownika z pamięci podręcznej ...
Nilesh Kikani
10

Jeśli używasz NSURLConnection, spójrz na delegata:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse

Wartość zwracana

Rzeczywista odpowiedź z pamięci podręcznej do zapisania w pamięci podręcznej. Delegat może zwrócić niezmodyfikowaną odpowiedź cachedResponse, zwrócić zmodyfikowaną odpowiedź w pamięci podręcznej lub zwrócić wartość nil, jeśli żadna buforowana odpowiedź nie powinna być przechowywana dla połączenia.

catlan
źródło
Dziękuję bardzo. Ślad pamięci mojej aplikacji nagle zmniejszył się o połowę! Nacięcie.
Nick Cartwright
9

Jeśli używasz NSURLSession, innym rozwiązaniem, aby zapobiec zapisywaniu żądań i parametrów do systemu Cache.dbiOS tworzonego w katalogu aplikacji Caches, jest ustawienie NSURLCachekonfiguracji sesji na pamięć o rozmiarze 0 i pamięć podręczną dysku o rozmiarze 0, np.

let configuration = URLSessionConfiguration.default    
configuration.urlCache = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)
let session = URLSession(configuration: configuration)

lub, jak wspomniano powyżej, ustawiono na globalnym poziomie pamięci podręcznej

URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)

Prawdopodobnie jest to 0 dla rozmiaru dysku, który zatrzymuje zapisywanie na dysku przez iOS, ale jeśli masz zasady reloadIgnoringLocalCacheData, prawdopodobnie nie jesteś zainteresowany buforowaniem pamięci.

Uwaga Zapobiegnie to tworzeniu jakichkolwiek Caches/Cache.db(żądań i odpowiedzi) lub Caches/fsCachedData/folderów (dane odpowiedzi). Zdecydowaliśmy się zastosować to podejście w aplikacji ze względów bezpieczeństwa, ponieważ nie chcemy, aby nasze żądania były nigdy przechowywane w pamięci podręcznej dysku.

Jeśli ktoś wie, czy istnieje sposób, aby zatrzymać buforowanie tylko żądań, ale zachować buforowanie danych odpowiedzi z mechanizmu ładowania adresu URL iOS, chciałbym wiedzieć. (nie ma API ani oficjalnej dokumentacji na ten temat z tego, co mogę powiedzieć)

Shagun Madhikarmi
źródło
7

Jeśli nie jest to specyficzne dla pojedynczego żądania (chcesz wyłączyć pamięć podręczną dla całej aplikacji), poniżej jedna jest najlepszą opcją.Dodaj ten kod w delegacie aplikacji lub w oparciu o potrzeby w dowolnym miejscu

        int cacheSizeMemory = 0*4*1024*1024; // 0MB
        int cacheSizeDisk = 0*32*1024*1024; // 0MB
        NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
        [NSURLCache setSharedURLCache:sharedCache];
Sanjeev Rao
źródło
7
U mnie działa świetnie, ale możesz po prostu użyć 0, zamiast wykonywać mnożenie, które i tak kończy się na 0.
Gary Riches
1
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] url];
[request setValue:@"no-store" forHTTPHeaderField:@"Cache-Control"];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];

Zakładając, że serwer jest poprawnie zaimplementowany, umieszczenie Cache-Control:no-storenagłówka w żądaniu wygeneruje odpowiedź serwera z takim samym nagłówkiem, co spowoduje, NSURLCacheże dane odpowiedzi nie zostaną zapisane na dysku.

Dlatego nie ma potrzeby stosowania metody strzelby polegającej na wyłączaniu NSURLCachebuforowania dysku.

PS: Dodanie nagłówka powinno działać dla wszystkich frameworków HTTP, takich jak AFNetworking

Yuri Brigance
źródło