2010-12-05 5 views
0

Je suis nouveau au développement et ne peut pas comprendre cela:Pourquoi ce code ne fuit-il pas?

for(NSString *collectionName in jsonObjects) 
    { 
    NSDictionary *collection = [[NSDictionary alloc] init]; 
    collection = [jsonObjects valueForKey:collectionName]; 
    NSArray *items = [[NSArray alloc] initWithArray:[collection valueForKey:@"items"]]; 
    NSNumber *lastAccess = [[NSNumber alloc] init]; 

    lastAccess = [collection valueForKey:@"lastAccess"]; 

    [items release]; 
    } 

Je ne comprends pas pourquoi il est, que quand je ne divulguons soit lastAccess ou collection, le programme se bloque avec l'erreur EXC_BAD_ACCESS ..., mais si je ne publie pas articles J'ai une fuite. Quelqu'un peut-il s'il vous plaît faire la lumière sur cela. Je pensais que si vous utilisiez alloc, alors vous étiez propriétaire de la référence et devez donc libérer?

Répondre

1
for(NSString *collectionName in jsonObjects) 
{ 
    NSDictionary *collection = [[NSDictionary alloc] init]; // Allocation 
    collection = [jsonObjects valueForKey:collectionName]; // overwriting above, LEAKS 
    NSArray *items = [[NSArray alloc] initWithArray:[collection valueForKey:@"items"]]; // Allocation 
    NSNumber *lastAccess = [[NSNumber alloc] init]; // Allocation 
    lastAccess = [collection valueForKey:@"lastAccess"]; // overwriting above, LEAKs 
    [items release]; 
} 

appels qui ne contiennent pas « alloc » ou « nouveau » retour des références à l'objet qui sont « autoreleased » ce qui signifie qu'ils ne sont pas la propriété de vous, de les libérer provoqueront un accident. Vous pouvez les utiliser, mais seulement dans le cadre de la fonction que vous êtes, si vous en avez besoin pour une utilisation ultérieure, vous devrez appeler retain sur eux. Ainsi, lorsque vous appelez des fonctions d'accesseur, vous n'avez qu'à déclarer les variables dont vous avez besoin et à ne pas créer de nouveaux objets.

alloc crée un nouvel objet, dans le cas de collection vous créez un NSDictionary vide, mais vous écraser rapidement la référence à ce nouvel objet avec la référence autoreleased que vous obtenez de valueForKey: cela va créer une fuite. Comme l'objet créé à l'origine ne sera pas libéré.

probablement devrait ressembler à ceci

for(NSString *collectionName in jsonObjects) 
{ 
    NSDictionary *collection = [jsonObjects valueForKey:collectionName]; 
    NSArray *items = [collection valueForKey:@"items"]; 
    NSNumber *lastAccess = [collection valueForKey:@"lastAccess"]; 
} 

je me rends compte que, avec la capacité d'avoir des questions comme celle-ci a répondu par une foule prête à lire les manuels est devenu juste une corvée, mais si vous voulez vous progressez devrait avoir un Regardez, la plupart de la documentation Apple est exceptionnellement bien écrite que ces choses vont. Le memory management guide résoudra beaucoup de questions.

+0

Merci Harald, j'ai regardé le guide de gestion de la mémoire, mais mal compris je suppose :(I comprenez bien ce que vous dites à propos de l'écrasement de mon initial alloc/init, mais j'ai une question concernant la différence fonctionnelle entre NSDictionary * collection = [jsonObjects valueForKey: collectionName] et NSDictionary * collection = [NSDictionary dictionaryWithDictionary: [jsonObjects valueForKey : collectionName]]; ie ces deux déclarations sont-elles fonctionnellement équivalentes, la documentation ne le précise pas? – Beliskna

+0

Oui et non, les mêmes sont que les deux appels ne renvoient pas une référence à quelque chose que vous possédez (aucun d'entre eux ne contient 'alloc' ou 'new' ou 'copy', mais le premier crée un nouveau dictionnaire d l'initialise avec la valeur du dictionnaire donné (il s'appelle un 'constructeur de commodité'), le second renvoie juste le dictionnaire correspondant. [NSDictionary dictionaryWithDictionary: ...] est _different_ que [[NSDictionary alloc] initWithDictionary: ...] la seconde _does_ crée un objet que vous possédez –

+0

Merci Harald, vous avez été très utile. – Beliskna

0

Dans ce code, vous êtes juste en train de réaffecter le pointeur lastAccess, ce qui laisse le alloc ed NSNumber fuit. Vous devez définir la valeur de l'objet NSNumber pointé par lastAccess.

EDIT:

j'avais placé quelques exemples de code, mais je le sortir, car je me rends compte maintenant que l'exemple de code ci-dessus a trop de problèmes. Jetez un oeil à la documentation pour NSDictionary. Avec collection, vous créez un objet, puis vous le fuyez en réaffectant son pointeur sur autre chose. Une fois ces problèmes résolus, je recommande de mettre à jour la question avec le nouveau code.

4

Il y a beaucoup de problèmes avec ce code. Ignorer, pour le moment, que la Fondation met en cache certaines valeurs couramment utilisées.

Ce modèle n'a pas de sens:

NSDictionary *collection = [[NSDictionary alloc] init]; 
collection = [jsonObjects valueForKey:collectionName]; 

La première ligne crée un (vide) instance de NSDictionary et la deuxième ligne rapidement la référence écrase à elle. A la fois une fuite et totalement inutile; il n'y a pas besoin d'affectation/affectation sur la première ligne. Idem pour lastAccess plus tard.

Étant donné que la deuxième ligne renvoie une référence non-propriétaire, tenter de release provoquera un blocage.

Notez que s'il y a un plantage, il y aura un backtrace. Cette question est assez simple pour dire que ce n'est pas nécessaire, mais regardez toujours la trace pour trouver des indices.

Notez que vous ne verrez pas de fuite des instances NSNumber ou NSDictionary, car la fondation en possède des exemples. Dans le cas NSNumber, cela n'a aucun sens. Les dictionnaires vides, cependant, sont utilisés assez souvent et avoir un singleton sauve la mémoire.

+0

Merci de revenir à moi bbum, je ne suis pas sûr de ce que sont les singletons, mais je vais vérifier les docs :) – Beliskna

0

Après @bbum ci-dessus, je voudrais écrire votre code comme ceci:

for(NSString *collectionName in jsonObjects) 
{ 
NSDictionary *collection = [jsonObjects valueForKey:collectionName]; 
NSArray *items = [NSArray arrayWithObject:[collection valueForKey:@"items"]]; 
NSNumber * lastAccess = [collection valueForKey:@"lastAccess"]; 
} 

Toutes les variables dans ce cas seront autoreleased, de sorte que vous n'avez pas besoin de le faire manuellement les libérer.

Questions connexes