2010-05-28 6 views
3

Je construis un tableau de dictionnaires (appelés touches) dans mon application iphone pour contenir les noms de section et les comptes de lignes pour une vue de table.Classe de collecte efficace de mémoire

le code ressemble à ceci:

[self.results removeAllObjects]; 
[self.keys removeAllObjects]; 

NSUInteger i,j = 0; 
NSString *key = [NSString string]; 
NSString *prevKey = [NSString string]; 

if ([self.allResults count] > 0) 
{ 
    prevKey = [NSString stringWithString:[[[self.allResults objectAtIndex:0] valueForKey:@"name"] substringToIndex:1]]; 

    for (NSDictionary *theDict in self.allResults) 
    { 
     key = [NSString stringWithString:[[theDict valueForKey:@"name"] substringToIndex:1]]; 

     if (![key isEqualToString:prevKey]) 
     { 
      NSDictionary *newDictionary = [NSDictionary dictionaryWithObjectsAndKeys: 
              [NSNumber numberWithInt:i],@"count", 
              prevKey,@"section", 
              [NSNumber numberWithInt:j], 
              @"total",nil]; 

      [self.keys addObject:newDictionary]; 
      prevKey = [NSString stringWithString:key]; 
      i = 1; 
     } 
     else 
     { 
      i++; 
     } 
     j++; 

    } 

    NSDictionary *newDictionary = [NSDictionary dictionaryWithObjectsAndKeys: 
            [NSNumber numberWithInt:i],@"count", 
            prevKey,@"section", 
            [NSNumber numberWithInt:j], 
            @"total",nil]; 

    [self.keys addObject:newDictionary]; 

} 

[self.tableview reloadData]; 

Le code fonctionne très bien la première fois à travers mais je dois parfois reconstruire toute la table, donc je refais ce code qui Orks bien sur le simulateur, mais sur mon appareil le bombes programme quand j'exécute la ligne reloadData:

malloc: *** mmap(size=3772944384) failed (error code=12) 
*** error: can't allocate region 
*** set a breakpoint in malloc_error_break to debug 
malloc: *** mmap(size=3772944384) failed (error code=12) 
*** error: can't allocate region 
*** set a breakpoint in malloc_error_break to debug 
Program received signal: “EXC_BAD_ACCESS”. 

Si je supprime la reloadData Tapisser le code fonctionne sur l'appareil. Je me demande si cela a quelque chose à voir avec la façon dont j'ai construit le tableau de clés (c'est-à-dire en utilisant des chaînes et des dictionnaires auto-libérés).

Répondre

15

Le message d'erreur vous donne une raison très clairement pourquoi l'allocation a échoué:

malloc: *** mmap(size=3772944384) failed (error code=12) 
*** error: can't allocate region 
*** set a breakpoint in malloc_error_break to debug 
malloc: *** mmap(size=3772944384) failed (error code=12) 
*** error: can't allocate region 

Plus précisément, la taille est 3772944384; presque 4GB. C'est à dire. vous demandez à malloc() d'allouer quelque chose qui oblige malloc à penser qu'il a besoin de carte mémoire (mmap) de près de 4Go d'espace d'adressage!

Maintenant, si vos chaînes d'entrée sont vraiment sacrément énorme, votre code sera ballonnements les piscines autorelease comme dit davydotcom, mais il leur faudrait vraiment vraiment énorme pour causer que cela se produise. Et si c'est si énorme, alors vous vous retrouvez avec des dizaines de milliers ou des centaines de milliers de lignes dans votre table? Si c'est le cas, ne faites pas cela - c'est trop dur pour l'utilisateur de travailler avec.

Comme l'indique l'erreur, définissez un point d'arrêt sur malloc_error et publiez une backtrace.

Notez que ceci:

NSString *key = [NSString string]; 
NSString *prevKey = [NSString string]; 

est absurde. OK - un deuxième coup d'œil sur votre code indique qu'un examen du guide Objective-C guide et du guide Cocoa memory management serait utile.

Dans les quatre premières lignes de code, vous fuyez le précédent et sur-conserver le nouveau self.keys et self. self.results (en supposant que les deux sont retain propriétés, comme ils devraient être). Essayez également d'utiliser Build & Analysez votre code.

+0

+1 pour les questions d'utilisabilité –

+0

les chaînes sont très petites et il y a environ 500 lignes dans la table. Je vais essayer le point d'arrêt ... – Joe

+0

OK - cela peut être un cas de fuites au fil du temps, aussi. Ou il peut s'agir d'un objet sur-relâché qui amène alors quelqu'un à demander un malloc ridicule(). Zombies & the Allocations vous aidera probablement beaucoup aussi. – bbum

0

Dans la mesure du possible, je recommande fortement de ne pas utiliser de chaînes et d'objets auto-libérés en général, car ils diminuent également les performances. Tout dans votre ensemble de code semble correct, sauf pour la déclaration impaire en haut.

les 2 premières lignes supprimer tous les objets des tableaux, alors vous attribuer des pointeurs vers de nouveaux self.keys et self.results

assignent les self.keys et self.results qu'une seule fois et lors du rechargement des données appellent simplement removeAllObjects .

+0

Conseil judicieux, mais pas le problème ici. – bbum

+1

Vous proposez d'optimiser les performances au prix de la lisibilité sans test. C'est un mauvais conseil. Les objets libérés automatiquement coûteront généralement une fraction d'un pour cent de performance, et (entre autres choses) répareraient plusieurs fuites de mémoire dans ce code que vous avez manqué et déclaré "tout semble correct". Autorelease est là pour une raison: Obtenir tout ce droit sans un modèle simple est * difficile *. –

+0

Vous avez raison sur les 2 lignes en haut (réaffectation des clés et des résultats). Ils étaient partis d'un test que je courais. Je les ai supprimés du code maintenant. – Joe

0

Un tableau de dictionnaires appelé clés ... [self.keys addObject: newDictionary] .. a besoin .. de .. down.

+1

Merci pour le downvote, je vois maintenant que c'est un schéma de nommage brillant, le problème est ailleurs. – hooleyhoop

+0

Problème est ailleurs, mais vous a donné upvote pour le commentaire drôle. Le schéma de nommage est horrible et a probablement fait déboguer ce problème plus difficile que ce qui était nécessaire :) – JOM

Questions connexes