Objective-C: Fixation gestion de la mémoire dans une méthode

voix
5

Je suis presque comprendre là comptage simple de référence / gestion de la mémoire en Objective-C, mais je suis un moment difficile avec le code suivant. Je libération mutableDict (commenté dans le code ci-dessous) et il est à l'origine des comportements préjudiciables dans mon code. Si je laisse la fuite de mémoire, il fonctionne comme prévu, mais qui est clairement pas la réponse ici. ;-) Est-ce que l'un de vous des gens plus expérimentés assez aimable pour me diriger dans la bonne direction que la façon dont je peux ré-écrire tout de cette méthode pour mieux gérer mon empreinte mémoire? Principalement avec la façon dont je gère NSMutableDictionary * mutableDict, comme c'est le grand coupable ici. Je voudrais comprendre le problème, et non pas seulement copier / coller du code - de sorte que certains commentaires / commentaires est idéal. Merci a tous.

- (NSArray *)createArrayWithDictionaries:(NSString *)xmlDocument 
                               withXPath:(NSString *)XPathStr {

    NSError *theError = nil;
    NSMutableArray *mutableArray = [[[NSMutableArray alloc] init] autorelease];
    //NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
    CXMLDocument *theXMLDocument = [[[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError] retain]; 
    NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
    int i, j, cnt = [nodes count];
    for(i=0; i < cnt; i++) {
        CXMLElement *xmlElement = [nodes objectAtIndex:i];
        if(nil != xmlElement) {
            NSArray *attributes = [NSArray array];
            attributes = [xmlElement attributes];
            int attrCnt = [attributes count];
            NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
            for(j = 0; j < attrCnt; j++) {
                if([[[attributes objectAtIndex:j] name] isKindOfClass:[NSString class]]) 
                    [mutableDict setValue:[[attributes objectAtIndex:j] stringValue] forKey:[[attributes objectAtIndex:j] name]];
                else 
                    continue;
            }
            if(nil != mutableDict) {
                [mutableArray addObject:mutableDict];
            }
            [mutableDict release];  // This is causing bad things to happen.
        }
    }

    return (NSArray *)mutableArray;
}
Créé 26/02/2009 à 23:32
source utilisateur
Dans d'autres langues...                            


3 réponses

voix
5

Voici un équivalent de réécriture du code:

- (NSArray *)attributeDictionaries:(NSString *)xmlDocument withXPath:(NSString *)XPathStr {
    NSError *theError = nil;
    NSMutableArray *dictionaries = [NSMutableArray array];
    CXMLDocument *theXMLDocument = [[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError]; 
    NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];

    for (CXMLElement *xmlElement in nodes) {
        NSArray *attributes = [xmlElement attributes];
        NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
        for (CXMLNode *attribute in attributes) {
            [attributeDictionary setObject:[attribute stringValue] forKey:[attribute name]];
        }

        [dictionaries addObject:attributeDictionary];
    }

    [theXMLDocument release];
    return attributeDictionaries;
}

Remarquez que je ne l'ai fait référence à compter sur theXMLDocument. En effet , les tableaux et les dictionnaires vivent au - delà de la portée de cette méthode. Les arrayet dictionaryméthodes de classe créer des instances de autoreleased NSArrayet des NSMutableDictionaryobjets. Si l'appelant ne les conservent explicitement, ils seront libérés automatiquement sur le prochain go-round de la boucle d'événements de l'application.

  • Je le code aussi enlevé qui n'a jamais été va être exécuté. La CXMLNode nameméthode dit qu'il retourne une chaîne, de sorte que ce test sera toujours vrai.
  • Si mutableDictest nil, vous avez des problèmes plus graves. Il est préférable qu'elle déclenche une exception que faillir en silence, je supprima ce test, aussi.
  • J'ai aussi utilisé relativement nouvelle forsyntaxe d'énumération, qui supprime vos variables compteur.
  • Je renomme certaines variables et la méthode pour être un peu plus Cocoa-ish. Le cacao est différent de la plupart des langues en ce qu'il est généralement considéré comme incorrect d'utiliser un verbe comme « créer » à moins que vous voulez spécifiquement faire l'appelant responsable de la libération quel objet vous revenez.
  • Vous ne faites rien avec theError. Vous devez soit vérifier et signaler l'erreur, ou bien passer nilsi vous ne va pas vérifier. Il n'y a pas de sens à faire l'application construire un objet d'erreur que vous ne comptez pas utiliser.

J'espère que cela aide à obtenir vous l'avez fait dans la bonne direction.

Créé 27/02/2009 à 00:18
source utilisateur

voix
1

Eh bien, la libération mutableDict ne devrait vraiment pas causer des problèmes parce que la ligne au-dessus (en ajoutant mutableDict à mutableArray) conservera automatiquement. Bien que je ne suis pas sûr exactement ce qui se passe mal avec votre code (vous ne spécifiez pas ce « mauvaises choses » signifie), il y a quelques choses générales je suggère:

  1. Ne pas AutoRelease mutableArray tout de suite. Que ce soit une déclaration alloc / init régulière et autorelease quand vous le retourner ( "return [mutableArray autorelease];").

  2. theXMLDocument fuit, assurez-vous de libération qui, avant de revenir. En outre, vous n'avez pas besoin de le retenir comme vous êtes. alloc / init fait le travail en démarrant l'objet à conserver le nombre 1, en conservant à nouveau juste assure qu'il fuit toujours. Débarrassez-vous de la conserver et de le libérer avant de revenir et il ne coulera pas.

  3. Juste un conseil: assurez-vous que vous conservez la valeur de retour de cette méthode lors de son utilisation ailleurs - le résultat a été autoreleased comme n'est pas garanti d'être là quand vous en avez besoin, sauf si vous conservez explicitement / libériez quelque part.

Dans le cas contraire, ce code devrait fonctionner. Si cela ne fonctionne toujours pas, un autre fait peut - être que je voudrais essayer [mutableArray addObject: [mutableDict copier]] pour faire en sorte que mutableDict vous pose pas de problème quand il est libéré.

Créé 26/02/2009 à 23:49
source utilisateur

voix
0

Dans Guide de programmation gestion de la mémoire sous la rubrique retour d' objets à partir de méthodes (défiler vers le bas un peu), il y a quelques exemples simples sur la façon de retourner des objets à partir d' une méthode avec la gestion de la mémoire correcte.

Créé 08/09/2010 à 22:48
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more