2010-11-24 8 views
0

Dans l'une de mes applications pour iPad, je construis la db à distance en utilisant une chaîne json puis convertie en NSArray pour l'insérer dans les données de base puis je charge 600Mb d'images sur l'ipad. Tout cela est créé dans un fil d'arrière-plan provoquant dès le départ un problème de mémoire. Je reçois le problème d'emboîtement de 3 NSAutoreleasePool différents dans l'opération et libère chacun d'eux à un point commode. Je n'ai eu aucune erreur, ni fuite, ni avertissement. Je me demandais simplement si c'était une bonne façon de le faire ou si je manquais quelque chose.imbriqué NSAutoreleasePool

Voici un exemple schématique (le code réel est assez long):

- (void)main{ 
@try { 


    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // first pool 
    [managedOC lock]; 
    NSArray *results = [self loadEntitiesWithGroupName:@"Project" andName:@"projects"]; 
    NSAutoreleasePool *prjPool; // second pool 
    for (NSDictionary *thisResult in results) { 
     prjPool = [[NSAutoreleasePool alloc] init]; 

     Project *prj = [[Project alloc] initWithEntity:[NSEntityDescription entityForName:@"Project" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext:self.managedOC]; 
     prj.name = [thisResult objectForKey:@"name"]; 
     [prj saveThumbnail:[thisResult objectForKey:@"thumbnail"]]; 

     //Slides. Those are the images that take so mutch space. 
     NSArray *slides = [thisResult objectForKey:@"slides"]; 
     NSAutoreleasePool *slidePool; // third pool 
     if(slides != kCFNull){ 
      slidePool = [[NSAutoreleasePool alloc] init]; 
      for(NSDictionary *slide in slides){ 
       Slide *thisSlide = [[Slide alloc] initWithEntity:[NSEntityDescription entityForName:@"Slide" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext: self.managedOC]; 
       thisSlide.path = prj.path; 
       [thisSlide saveFile:[slide objectForKey:@"file"]]; 
       [prj addSlidesObject:thisSlide]; 
       [thisSlide release]; 
       [slidePool drain]; 
      } 
     } 

     [prj release]; 
     [result release]; 
     [prjPool drain]; 


    } 

    [self.managedOC unlock]; 
    [totResult release]; 
    [pool drain]; 
} 
@catch (NSException * e) { 

} 
+0

Où et comment vous réellement télécharger des images? – Vladimir

+0

il est fait sur [thisSlide saveFile: [slide objectForKey: @ "fichier"]] où je crée l'UIImage à partir du fichier téléchargé puis j'utilise NSData et NSFileManager pour enregistrer sur le dossier Documents de l'application. – cescofry

Répondre

1

Je suis surpris de votre code ne tombe pas en panne. -drain se comporte comme -release dans l'environnement de référence compté, donc les lignes suivantes sur les rejets de la piscine

slidePool = [[NSAutoreleasePool alloc] init]; // this is in the wrong place 
for(NSDictionary *slide in slides){ 
    Slide *thisSlide = [[Slide alloc] initWithEntity:[NSEntityDescription entityForName:@"Slide" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext: self.managedOC]; 
    thisSlide.path = prj.path; 
    [thisSlide saveFile:[slide objectForKey:@"file"]]; 
    [prj addSlidesObject:thisSlide]; 
    [thisSlide release]; 
    [slidePool drain]; 
} 

moins qu'il n'y ait qu'un seul objet dans la collection slides. Vous avez besoin de ceci:

for(NSDictionary *slide in slides){ 

    slidePool = [[NSAutoreleasePool alloc] init]; // this is in the right place 

    Slide *thisSlide = [[Slide alloc] initWithEntity:[NSEntityDescription entityForName:@"Slide" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext: self.managedOC]; 
    thisSlide.path = prj.path; 
    [thisSlide saveFile:[slide objectForKey:@"file"]]; 
    [prj addSlidesObject:thisSlide]; 
    [thisSlide release]; 
    [slidePool drain]; 
} 

À part cela, vous avez la bonne idée générale.

Vous devez vider votre piscine extérieure dans le bloc finally de votre gestionnaire d'exceptions afin qu'il ne soit pas ignorée si une exception est soulevée à savoir que vous devez faire ceci:

- (void)main{ 

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // first pool 

    @try { 

     // Do al your stuff 
    } 
    @catch (NSException * e) { 

    } 
    @finally 
    { 
     [pool drain]; 
    } 
} 
+0

Vous avez raison à propos de la position de slidePool, mais le code ne s'est jamais écrasé. Merci aussi pour le bit @finally. Quoi qu'il en soit, est-il correct d'appliquer plusieurs pools autorelease imbriqués comme je l'ai fait? – cescofry

+0

@cescofry: Oui, mis à part le mauvais emplacement de l'allocation de slidePool, ça va. – JeremyP