2011-08-11 7 views
0

Je suis un débutant à Obj-C, et j'expérimente avec peu de choses. Je suis tombé sur un problème de fuite et j'aimerais en connaître la raison logique.Objectif - C - NSMutableAttributedString Leak

La pièce de code suivant fuites:

(textViewAttrStr is an instance variable of type NSMutableAttributedString) 

-(void) init:(NSString*)str 
{ 
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

textViewAttrStr = [[NSMutableAttributedString alloc] initWithString:@"Hello "]; 
NSMutableAttributedString *part1String = [[NSMutableAttributedString alloc] initWithString:str]; 
[textViewAttrStr appendAttributedString:part1String]; 
NSMutableAttributedString *part2String = [[NSMutableAttributedString alloc] initWithString:@"!!!"]; 
[textViewAttrStr appendAttributedString:part2String]; 
[textViewAttrStr retain]; 

[part1String release]; 
[part2String release]; 

[pool drain]; 
} 

-(void) dealloc 
{ 
if(textViewAttrStr != nil) 
{ 
    [textViewAttrStr release]; 
} 

[super dealloc]; 
} 

alors que le code suivant ne fuit pas:

-(void) init:(NSString*)str 
{ 
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

NSMutableAttributedString* tvas = [[NSMutableAttributedString alloc] initWithString:@"Hello "]; 
NSMutableAttributedString *part1String = [[NSMutableAttributedString alloc] initWithString:str]; 
[tvas appendAttributedString:part1String]; 
NSMutableAttributedString *part2String = [[NSMutableAttributedString alloc] initWithString:@"!!!"]; 
[tvas appendAttributedString:part2String]; 

textViewAttrStr = tvas; 
[textViewAttrStr retain]; 

[part1String release]; 
[part2String release]; 
[tvas release]; 

[pool drain]; 
} 

-(void) dealloc 
{ 
if(textViewAttrStr != nil) 
{ 
    [textViewAttrStr release]; 
} 

[super dealloc]; 
} 

Quelqu'un peut-il expliquer pourquoi?

+0

Merci à tous pour vos réponses rapides. Cela rend la gestion de la mémoire un peu plus facile pour moi. :) –

Répondre

0

Votre deuxième exemple montre que vous ne comprenez pas pourquoi vous avez une fuite dans le premier exemple, si vous avez choisi d'expérimenter autour, ce qui semble être une approche compréhensible. Dans votre deuxième exemple, textViewAttrStr et tavs sont essentiellement les mêmes. Ils sont tous deux des références (ou des pointeurs) au même objet en mémoire.

Alors, quand vous faites:

textViewAttrStr = tvas; 
[textViewAttrStr retain]; 
//... 
[tvas release]; 

L'appel à conserver sur cet objet est équilibré avec l'appel à libérer sur cet objet. C'est à peu près ne rien faire. La suppression des appels de conservation et de libération ici fournit la même fonctionnalité. Une fois que vous les supprimez, votre objet a un nombre de références de 1 parce que vous avez appelé alloc, et lorsque dealloc est atteint, il atteint 0 et est libéré. Maintenant, dans votre premier exemple, votre objet est alloué (nombre de références de 1), puis conservé (nombre de références de 2), et quand dealloc atteint, il atteindra le nombre de références de 1 et votre objet sera ne pas être libéré et donc fuir. Donc la solution ici est de supprimer l'appel à retenir. D'ailleurs, vérifier si les objets ne sont pas nuls avant d'envoyer un message de libération est inutile car l'envoi d'un message à zéro ne fait rien.

1

Premier exemple:

textViewAttrStr = [[NSMutableAttributedString alloc] initWithString:@"Hello "]; 
//... 
[textViewAttrStr retain]; 

Deuxième exemple

NSMutableAttributedString* tvas = [[NSMutableAttributedString alloc] initWithString:@"Hello "]; 
//... 
[tvas release]; 

Vous devriez maintenant voir que dans votre premier exemple, vous avez alloc/init'd et le retenaient, oups.

Deuxième exemple, vous allouez/init'd puis libérez correctement.

Règle simple: Si vous allouez/init OU copiez OU conservez, vous devez libérer à un moment donné. S'il s'agit d'une variable de classe, relâchez-la dans dealloc, sinon relâchez-la avant de quitter la portée.

2

Le problème avec le premier exemple est la retenue supplémentaire. Vous devez supprimer ce parce qu'il est déjà retenue lorsque vous créez le textViewAttrStr avec [[NSMutableAttributedString alloc] initWithString:@"Hello "];

//Remove this line in the first example 
[textViewAttrStr retain];