2009-06-20 8 views
3

Mise à jour: J'ai modifié le code, mais le problème persiste ...fuite de mémoire étrange iPhone dans l'analyseur XML

Salut tout le monde,
c'est mon premier post ici - j'ai trouvé cet endroit un grand ressource pour résoudre beaucoup de mes questions. Normalement, je fais de mon mieux pour résoudre tout seul, mais cette fois je n'ai aucune idée de ce qui ne va pas, alors j'espère que quelqu'un pourra m'aider.
Je suis la construction d'une application iPhone qui analyse quelques fichiers XML en utilisant TouchXML. J'ai une classe XMLParser, qui s'occupe du téléchargement et de l'analyse des résultats. Je reçois des fuites de mémoire lorsque j'analyse un fichier XML plusieurs fois avec la même instance de XMLParser. Voici l'un des extraits d'analyse syntaxique (seulement la partie pertinente):

for(int counter = 0; counter < [item childCount]; counter++) { 
     CXMLNode *child = [item childAtIndex:counter]; 
     if([[child name] isEqualToString:@"PRODUCT"]) 
     { 
      NSMutableDictionary *product = [[NSMutableDictionary alloc] init]; 
      for(int j = 0; j < [child childCount]; j++) { 
       CXMLNode *grandchild = [child childAtIndex:j]; 
       if([[grandchild stringValue] length] > 1) { 
        NSString *trimmedString = [[grandchild stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 
        [product setObject:trimmedString forKey:[grandchild name]]; 
       } 
      } 

      // Add product to current category array 
      switch (categoryId) { 
       case 0: 
        [self.mobil addObject: product]; 
        break; 
       case 1: 
        [self.allgemein addObject: product]; 
        break; 
       case 2: 
        [self.besitzeIch addObject: product]; 
        break; 
       case 3: 
        [self.willIch addObject: product]; 
        break; 
       default: 
        break; 
      } 
      [product release]; 
     } 

    } 

La première fois, je parse le code XML aucune fuite apparaît dans les instruments, la prochaine fois que je le fais, je me suis beaucoup de fuites (NSCFString/NSCFDictionary).
Instruments me dirige à l'intérieur cette partie CXMLNode.m, quand je creuse dans un objet de fuite:

theStringValue = [NSString stringWithUTF8String:(const char *)theXMLString]; 
if (_node->type != CXMLTextKind) 
    xmlFree(theXMLString); 
} 

return(theStringValue); 

J'ai vraiment passé beaucoup de temps et ont essayé plusieurs approches pour résoudre ce problème, mais en vain jusqu'à présent , peut-être qu'il me manque quelque chose d'essentiel?

Toute aide est très appréciée, merci!

Répondre

3

La question est probablement dans cette ligne: cependant,

[self.mobil addObject:[product copy]]; 

En appelant une copie de product vous créez une nouvelle instance NSMutableDictionary avec un nombre de retenir 1. L'instance mobil, incrémente la le nombre de retenues de la copie lorsque vous lui envoyez le message addObject:, de sorte que le nombre de rétention de la copie est maintenant 2. Généralement, un objet est responsable de la gestion de sa propre mémoire d'objet, donc chaque fois que vous message setFoo: ou addObject:, vous pouvez simplement passer le objet directement, même si son autoeleased ou vous envisagez de le libérer juste après l'appel; Il est de la responsabilité du receveur de retenir l'objet que vous passez s'il doit le conserver. Comme vous n'avez affecté aucune copie à une variable, vous n'avez pas de pointeur que vous pouvez utiliser pour réduire le nombre de réceptions de la copie maintenant que vous ne l'avez plus intéressé, même si mobil libère la copie du produit à un certain point, la copie n'atteindra jamais un nombre de retenue de 0. Votre instruction [product release] à la fin de la boucle for libère l'objet original product, pas la copie que vous avez créée.

Au lieu de cela, essayez ce qui suit et voir si des instruments est plus heureux:

[self.mobil addObject:product]; 
+0

Merci beaucoup - qui était stupide de ma part. Malheureusement les fuites existent toujours, mais maintenant à l'intérieur de la classe CXMLNode.m à cette ligne: theStringValue = [NSString stringWithUTF8String: (const char *) theXMLString]; if (_node-> type! = CXMLTextKind) \t xmlFree (theXMLString); } return (theStringValue); – Chris

+0

ah désolé, je ne pouvais pas obtenir le formatage correct ... – Chris

+0

Hmmm ... qui ressemble plus à un avertissement d'une fuite possible, plutôt que d'un poireau garanti. Cela dit, je suis passé en revue la source pour CXMLNode dans TouchXML et je ne trouve pas cette ligne du tout ... quelle version du projet avez-vous, et sur quelle ligne est-il? Je note du groupe d'utilisateurs google TouchCode que l'auteur, Jonathan Wight, est assez bon pour répondre aux messages re: fuites de mémoire: http://groups.google.com/group/touchcode-dev –

1

En termes simples, chaque fois que vous utilisez copy, vous devez également utiliser quelque part release/autorelease.

Et dans ce cas, la réponse encore plus facile est de ne pas utiliser copy en premier lieu, puisque vous ne faites rien avec la version originale de product après l'avoir copié.

1

J'ai résolu le problème moi-même.C'était un peu stupide, mais peut-être que quelqu'un pourrait rencontrer la même chose, alors je vais l'afficher ici.

1) Je l'avais mis en place mutable tableau comme variables d'instance comme celle-ci:

@interface XMLParser : NSObject { 

// ... 
NSMutableArray *mobil; 
// ... 
} 
@property(nonatomic, retain) NSMutableArray *mobil; 
@end 

Chaque fois que je voulais restaurer les nouvelles données à l'intérieur je l'ai fait:
self.mobil = nul;
Ce qui n'a pas ce que je voulais faire, c'est donc la meilleure approche:
[self.mobil removeAllObjects];

2) La méthode dealloc doit être comme celui-ci pour fixer les fuites (car mobile est définie comme une propriété):
- (void) {dealloc
[version mobile];
self.mobil = néant;
}

Ouf, qui a été beaucoup de travail pour savoir - espérons qu'il sauve quelqu'un d'autre quelque temps :-)