Nous créons une application iPad qui télécharge un ensemble de données et de documents PDF à partir d'un service Web (les données d'abord, les documents ensuite, en arrière-plan). Pour ce faire, nous utilisons SOAP via des requêtes HTTP(S). Cela fonctionne bien et, dans l'ensemble, l'application fonctionne bien. Le problème est que s'il y a trop de documents à télécharger à un moment donné, l'application se plante. En utilisant Instruments, j'ai découvert que c'est un problème de mémoire, en particulier NSRegularExpression et NSRunLoop. (J'utilise ARC)
Je pourrais améliorer mon code pour optimiser la création de NSRegularExpression. Mais je ne sais pas comment améliorer le problème du NSRunLoop.
J'ai essayé les deux, la demande HTTP asynchrone et synchrone. En utilisant l'asynchrone, j'ai dû attendre que le téléchargement se termine et comme sleep()/[NSThread sleepForTimeInterval :] ne sont pas une option, j'utilise
while ( _waitToFinish ) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
En utilisant la demande de synchronisation, Instruments révèle que
[NSURLConnection sendSynchronousRequest:theRequest returningResponse:&urlResponse error:&error];
attend également avec l'aide de NSRunLoop et perturbe également la mémoire.
S'agit-il d'un bogue dans CoreFoundation ou ARC ?
Existe-t-il un autre moyen de rester inactif en attendant que les requêtes se terminent ?
Merci d'avance.
Edit :
Par "problème de mémoire", je voulais dire que l'application se plante (ou est tuée par iOS) parce qu'elle utilise trop de mémoire.
C'est ce que montrent les instruments : Le pourcentage augmente avec la durée du téléchargement de l'application.
Edit :
En allant plus loin, on s'aperçoit que c'est la NSURLConnection qui perturbe la mémoire. Il semble que j'ai oublié de configurer connection
y receivedData
a nil
(voir Guide de programmation du système de chargement URL ). Cela a amélioré un peu l'utilisation de la mémoire.
Maintenant, il y a deux autres grandes opérations d'allocation de mémoire :
Et voici le code que je pense correspondre à ce qu'affiche Instruments :
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_receivedData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseText = [[NSString alloc] initWithBytes:[_receivedData mutableBytes] length:[_receivedData length] encoding:NSUTF8StringEncoding];
self.lastResponse = responseText;
responseText = nil;
connection = nil;
_receivedData = nil;
_lastResult = TRUE;
_waitToFinish = FALSE;
}
Y a-t-il quelque chose que je puisse changer pour améliorer le code ?
Edit : (Titre modifié de "NSRunLoop mess up iPad memory")
Edit : J'ai créé une application de test pour prouver que c'est la NSURLConnection qui perturbe la mémoire. J'ai ensuite contacté le support aux développeurs d'Apple.
Comme je télécharge un grand nombre de PDF dans une itération avec NSURLConnection, la solution a été d'ajouter une balise @autoreleasepool { .. }
dans l'itération et un autre autour de la NSRunLoop
.
Merci.