¿Es posible evitar que una NSURLRequest almacene datos en caché o elimine datos almacenados en caché después de una solicitud?

89

En iPhone, realizo una solicitud HTTP usando NSURLRequest para una gran cantidad de datos. La asignación de objetos aumenta y asigno los datos en consecuencia. Cuando termino con los datos, los libero en consecuencia; sin embargo, los instrumentos no muestran ningún dato que se haya liberado.

Mi teoría es que, de forma predeterminada, las solicitudes HTTP se almacenan en caché, sin embargo, no quiero que mi aplicación de iPhone almacene en caché estos datos.

¿Hay alguna manera de borrar este caché después de una solicitud o evitar que se almacenen en caché en primer lugar?

Intenté usar todas las políticas de caché documentadas un poco como a continuación:

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

¡pero nada parece liberar la memoria!

Nick Cartwright
fuente
¿Sería posible que no esté relacionado con la caché? ¿Ha intentado inspeccionar los datos para ver si los datos que deberían haberse recargado son en realidad los antiguos? Quizás su puerro venga de otra parte. ¿Cómo se inicializan y liberan las NSURLRequests? Eso podría ser de ayuda para diagnosticar el problema.
lpfavreau
FYI: si desea eliminar los archivos por fuerza bruta, hay un código de ejemplo para hacerlo aquí: salesforce.stackexchange.com/a/69736
zekel

Respuestas:

157

Por lo general, es más fácil crear la solicitud de esta manera.

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

Luego crea la conexión

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

e implementar el método connection: willCacheResponse: en el delegado. Solo devolver cero debería hacerlo.

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
  return nil;
}
tcurdt
fuente
¡Muchas gracias por tu ayuda! Mella.
Nick Cartwright
1
Gracias por esa idea, estaba llamando a un servicio web SOAP como este repetidamente y estaba creciendo incontrolablemente a pesar de que las filtraciones no mostraban que nada estaba mal. Optimicé durante días y finalmente traté de evitar el almacenamiento en caché, ya que había muchos objetos CFURL * del marco interno. ¡Devolver nada de willCacheResponse fue lo único que funcionó!
Bron Davies
15
¿Por qué es necesario hacer ambas cosas NSURLRequestReloadIgnoringCacheData e implementarlas connection:willCacheResponse:?
fabb
1
Hola, ¿es posible que pueda usar esto para cargar contenido local? Lo anterior es para NSUrlConnection pero estoy cargando datos HTML locales en UIWebView usando NSUrlRequest. Necesito rechazar cualquier almacenamiento en caché ya que hay imágenes que ingresan a la vista web desde SQLite y la memoria aumenta con cada carga de página. Gracias.
jim
7
@fabb, la invalidación le connection:willCacheResponse:permite no almacenar la respuesta en el caché. NSURLRequestReloadIgnoringCacheDataespecifica que la conexión debe cargar la solicitud sin verificar la caché. El primero es presumiblemente lo que ayuda a administrar la asignación de memoria.
Christopher Pickslay
12

Tengo el mismo problema en mi aplicación cuando solicité información de Twitter. En mi caso, no necesitaba conservar esas credenciales, así que simplemente las borro usando el siguiente código:

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

Espero que funcione para alguien :)


fuente
esta fue una solución perfecta para mi problema, tuve un problema para volver a iniciar sesión, ya que las credenciales se almacenaron y NSURLConnection las enviaba automáticamente, muchas gracias, esto me ayudó mucho :)
RVN
Gracias, es un trabajo para mí, realmente aprecio tu sugerencia. En realidad, mi problema es que NSURLRequest almacena el nombre de usuario y la contraseña. Entonces, esta ayuda para eliminar la credencial de usuario de la caché ...
Nilesh Kikani
10

Si usa NSURLConnection, eche un vistazo al delegado:

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

Valor devuelto

La respuesta real en caché para almacenar en la caché. El delegado puede devolver cachedResponse sin modificar, devolver una respuesta en caché modificada o devolver nil si no se debe almacenar una respuesta en caché para la conexión.

catlan
fuente
Muchas gracias aqui ¡La huella de memoria de mi aplicación se ha reducido repentinamente a la mitad! Mella.
Nick Cartwright
9

Si está usando NSURLSession, otra solución para evitar que la solicitud y los parámetros se escriban en el Cache.dbiOS crea dentro del Cachesdirectorio de la aplicación , es establecer la configuración NSURLCachede la sesión en una memoria de tamaño 0 y una memoria caché de disco de tamaño 0, por ejemplo

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

o como se mencionó anteriormente establecido a nivel de caché global

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

Presumiblemente, es el 0 para el tamaño del disco lo que detiene la escritura de iOS en el disco, pero si tiene una política para hacerlo reloadIgnoringLocalCacheData, probablemente tampoco esté interesado en el almacenamiento en caché de la memoria.

Nota: Esto evitará que se creen Caches/Cache.db(solicitudes y respuestas) o Caches/fsCachedData/carpetas (datos de respuesta). Hemos decidido adoptar este enfoque en una aplicación por motivos de seguridad, ya que no queremos que nuestras solicitudes se almacenen nunca en la memoria caché del disco.

Si alguien sabe si hay una manera de detener solo el almacenamiento en caché de solicitudes pero mantener el almacenamiento en caché de los datos de respuesta del mecanismo de carga de URL de iOS, me interesaría saberlo. (no hay API o documentación oficial sobre esto por lo que puedo decir)

Shagun Madhikarmi
fuente
7

Si no es específico para una sola solicitud (si desea deshabilitar el caché para toda la aplicación), la mejor opción es la siguiente: agregue este código en el delegado de la aplicación o según su necesidad en cualquier lugar

        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
fuente
7
Funciona muy bien para mí, pero puedes usar 0 en lugar de hacer la multiplicación que termina en 0 de todos modos.
Gary Riches
1
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] url];
[request setValue:@"no-store" forHTTPHeaderField:@"Cache-Control"];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];

Suponiendo que el servidor está implementado correctamente, colocar el Cache-Control:no-storeencabezado en la solicitud generará una respuesta del servidor con el mismo encabezado, lo que provocará NSURLCacheque no se almacenen los datos de respuesta en el disco.

Por lo tanto, no es necesario el enfoque de escopeta de deshabilitar NSURLCacheel almacenamiento en caché de disco.

PD: Agregar el encabezado debería funcionar para todos los marcos HTTP, como AFNetworking

Yuri Brigance
fuente