Est-il possible d'empêcher une NSURLRequest de mettre des données en cache ou de supprimer des données mises en cache suite à une demande?

89

Sur iPhone, j'effectue une requête HTTP en utilisant NSURLRequest pour un morceau de données. Les pics d'allocation d'objets et j'attribue les données en conséquence. Lorsque j'en ai fini avec les données, je les libère en conséquence - cependant, les instruments ne montrent pas que les données ont été libérées!

Ma théorie est que par défaut, les requêtes HTTP sont mises en cache, cependant - je ne veux pas que mon application iPhone cache ces données.

Existe-t-il un moyen de vider ce cache après une demande ou d'empêcher la mise en cache des données en premier lieu?

J'ai essayé d'utiliser toutes les politiques de cache documentées un peu comme ci-dessous:

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

mais rien ne semble libérer la mémoire!

Nick Cartwright
la source
Serait-il possible que ce ne soit pas lié au cache? Avez-vous essayé d'inspecter les données pour voir si les données qui auraient dû être rechargées sont en fait les anciennes? Peut-être que votre poireau vient d'ailleurs. Comment initialiser et libérer les NSURLRequests? Cela pourrait aider à diagnostiquer le problème.
lpfavreau
FYI - Si vous souhaitez supprimer les fichiers par force brute, il existe un exemple de code pour le faire ici: salesforce.stackexchange.com/a/69736
zekel

Réponses:

157

Habituellement, il est plus facile de créer la demande comme ceci

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

Puis créez la connexion

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

et implémentez la méthode connection: willCacheResponse: sur le délégué. Le simple retour de zéro devrait le faire.

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
  return nil;
}
tcurdt
la source
Merci beaucoup ici pour votre aide! Pseudo.
Nick Cartwright le
1
Merci pour cette idée - j'appelais à plusieurs reprises un service Web SOAP comme celui-ci et il augmentait le tas de manière incontrôlable même si les fuites ne montraient pas que quelque chose n'allait pas. J'ai optimisé pendant des jours et j'ai finalement essayé d'empêcher la mise en cache car beaucoup d'objets CFURL * du framework interne traînaient. Renvoyer nil de willCacheResponse était la seule chose qui fonctionnait!
Bron Davies
15
Pourquoi est-il nécessaire de faire les deux NSURLRequestReloadIgnoringCacheData et de mettre en œuvre connection:willCacheResponse:?
fabb
1
Bonjour, est-il possible que je puisse l'utiliser pour charger du contenu local? Ce qui précède concerne NSUrlConnection mais je charge des données HTML locales dans UIWebView à l'aide de NSUrlRequest. Je dois rejeter toute mise en cache car il y a des images qui entrent dans la vue Web à partir de SQLite et la mémoire augmente à chaque chargement de page. Merci.
jim
7
@fabb, le remplacement connection:willCacheResponse:vous permet de ne pas stocker la réponse dans le cache. NSURLRequestReloadIgnoringCacheDataspécifie que la connexion doit charger la demande sans vérifier le cache. Le premier est probablement ce qui aide à gérer l'allocation de mémoire.
Christopher Pickslay
12

J'ai le même problème dans mon application lorsque j'ai demandé des informations à Twitter. Dans mon cas, je n'avais pas besoin de conserver ces informations d'identification, donc je les efface simplement en utilisant le code suivant:

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

J'espère que ça marche pour quelqu'un :)


la source
c'était une solution parfaite pour mon problème, j'avais un problème de connexion, car les informations d'identification étaient stockées et étaient automatiquement soumises par NSURLConnection, merci beaucoup cela m'a beaucoup aidé :)
RVN
Merci, c'est du travail pour moi, j'apprécie vraiment votre suggestion. En fait, mon problème est que NSURLRequest stocke le nom d'utilisateur et le mot de passe. Donc, cette aide pour supprimer les informations d'identification de l'utilisateur du cache ...
Nilesh Kikani
10

Si vous utilisez NSURLConnection, jetez un œil au délégué:

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

Valeur de retour

La réponse réelle mise en cache à stocker dans le cache. Le délégué peut renvoyer cachedResponse non modifié, renvoyer une réponse mise en cache modifiée ou renvoyer nil si aucune réponse mise en cache ne doit être stockée pour la connexion.

catlan
la source
Merci beaucoup ici. L'empreinte mémoire de mon application a soudainement diminué de moitié! Pseudo.
Nick Cartwright
9

Si vous utilisez NSURLSession, une autre solution pour empêcher la demande et les paramètres d'être écrits dans Cache.dbiOS crée dans le Cachesrépertoire de l'application , consiste à définir la configuration NSURLCachede la session sur une mémoire de taille 0 et un cache disque de taille 0, par exemple

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

ou comme mentionné ci-dessus défini à un niveau de cache global

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

C'est probablement le 0 pour la taille du disque qui arrête l'écriture d'iOS sur le disque, mais si vous avez une politique, reloadIgnoringLocalCacheDatavous n'êtes probablement pas non plus intéressé par la mise en cache de la mémoire.

Remarque Cela empêchera toute Caches/Cache.db(demandes et réponses) ouCaches/fsCachedData/ création de dossier (données de réponse). Nous avons décidé d'adopter cette approche dans une application à des fins de sécurité, car nous ne voulons jamais que nos demandes soient stockées sur le cache disque.

Si quelqu'un sait qu'il existe un moyen d'arrêter uniquement la mise en cache des demandes mais de conserver la mise en cache des données de réponse du mécanisme de chargement d'URL iOS, je serais intéressé de savoir. (il n'y a pas d'API ou de documentation officielle à ce sujet d'après ce que je peux dire)

Shagun Madhikarmi
la source
7

Si ce n'est pas spécifique à une seule demande (vous voulez désactiver le cache pour toute l'application) ci-dessous est la meilleure option.Ajoutez ce code dans le délégué d'application ou en fonction de votre besoin n'importe où

        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
la source
7
Fonctionne très bien pour moi, mais vous pouvez simplement utiliser 0 plutôt que de faire la multiplication qui se termine à 0 de toute façon.
Gary Riches du
1
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] url];
[request setValue:@"no-store" forHTTPHeaderField:@"Cache-Control"];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];

En supposant que le serveur est correctement implémenté, mettre l'en- Cache-Control:no-storetête dans la requête générera une réponse du serveur avec le même en-tête, provoquant ainsi le NSURLCachenon stockage des données de réponse sur le disque.

Par conséquent, pas besoin de l'approche fusil à pompe de désactivation NSURLCachede la mise en cache du disque.

PS: l'ajout de l'en-tête devrait fonctionner pour tous les frameworks HTTP, comme AFNetworking

Yuri Brigance
la source