2009-09-01 6 views
1

Ce code fonctionne:Comment suis-je en train de mal gérer la mémoire de mon iPhone?

monkey.h

@interface monkey : NSObject { 
NSNumber *monkeyRanch; 
} 
@property (nonatomic, retain) NSNumber *monkeyRanch; 
-(id) gatherTheMonkeys:(int)howmany; 

monkey.m

@synthesize monkeyRanch; 
-(id) gatherTheMonkeys:(int)howmany{ 
NSNumber *temp=[[NSNumber alloc] initWithInt:howmany]; 
monkeyRanch = temp; 
[temp release]; 
return [monkeyRanch autorelease]; 
} 

appDelegate.m

theMonkeys = [[monkey alloc] gatherTheMonkeys:3]; 
[window addSubview:[navigationController view]]; 
[window makeKeyAndVisible]; 

..et theMonkeys sont libérés dans dealloc. Il n'y a pas de fuite dans Instrument. Mais, si je tente la même chose avec un tableau NSMutable au lieu du NSNumber:

monkey.h

@interface monkey : NSObject { 
    NSMutableArray *monkeyRanch; 
} 
@property (nonatomic, retain) NSMutableArray *monkeyRanch; 
-(id) initTheMonkeys:(int)howmany; 

monkey.m @synthesize monkeyRanch;

-(id) initTheMonkeys:(int)howmany{ 
monkeyRanch=[[NSMutableArray alloc] init]; 
NSNumber *imp =[[NSNumber alloc] initWithInteger:howmany]; 
[monkeyRanch addObject:imp]; 
[imp release]; 
return [monkeyRanch autorelease]; 
} 

appDelegate

theMonkeys = [[monkey alloc] initTheMonkeys:3]; 
[theMonkeys retain]; 

cela provoque une fuite (d'un objet 'singe'), juste au début de l'application.

J'ai essayé de changer le initTheMonkeys à ce qui suit:

NSMutableArray *temp=[[NSMutableArray alloc] init]; 
monkeyRanch=temp; 
[temp release]; 
NSNumber *imp =[[NSNumber alloc] initWithInteger:howmany]; 
[monkeyRanch addObject:imp]; 
[imp release]; 
return [monkeyRanch autorelease]; 

mais le nombre de conserver monkeyRanch obtenu à zéro que la libération temporaire et l'application s'écrase joyeusement.

Qu'est-ce que je fais de mal, et comment puis-je le réparer?

+0

Que diable est un monkeyRanch? Était-ce censé être "monkeyWrench"? :) –

Répondre

3

Vos problèmes de mémoire se résument à un problème de propriété. Lorsqu'une classe a une variable d'instance (comme monkeyRanch), vous créez généralement une instance dans le initialiseur pour cette classe, puis relâchez-le dans dealloc, comme ceci:

@interface Monkey : NSObject { 
    NSMutableArray * monkeyRanch; 
} 
@end 

@implementation Monkey 
- (id)init { 
    if ((self = [super init]) == nil) { return nil; } 
    monkeyRanch = [[NSMutableArray alloc] initWithCapacity:0]; 
    return self; 
} 
- (void)dealloc { 
    [monkeyRanch release]; 
} 
@end 

Dans ce cas, la classe Monkey possède le membre monkeyRanch.

Dans les appels de fonction, vous devez être sûr de release des locaux objets que vous init, retain ou copy.Il semble que vous avez cette partie correcte, mais je vais vous montrer un exemple rapide tout de même:

- (void)someFunction { 
    NSNumber * myNumber = [[NSNumber alloc] init]; 
    ... 
    [myNumber release]; 
} 

La prochaine chose à comprendre est qu'il ya une différence énorme entre le réglage simplement une variable membre, et définir une valeur de propriété. C'est-à-dire:

NSMutableArray * temp = [[NSMutableArray alloc] initWithCapacity:0]; 
monkeyRanch = temp; 
[temp release]; // it's gone! 

est pas la même chose que:

NSMutableArray * temp = [[NSMutableArray alloc] initWithCapacity:0]; 
self.monkeyRanch = temp; // now owned by self 
[temp release]; 

Dans le premier cas, vous définissez simplement un pointeur (monkeyRanch) égal à un autre pointeur (temp). La valeur n'est pas conservée ou copiée.

Dans le second cas, vous définissez réellement la propriété. Cela signifie que, en supposant que la propriété a été définie pour conserver, le tableau est maintenant la propriété de votre objet de classe.

P.S .:

Vous pouvez également descendiez conception sage de la mauvaise voie. À mon avis, un ranch de singe est quelque chose qui a beaucoup de singes dedans. Si c'est vrai, alors vos objets Monkey ne devraient pas vraiment posséder le MonkeyRanch. Je plutôt aller avec quelque chose comme ceci:

Monkey.h

@class MonkeyRanch; 

@interface Monkey : NSObject { 
    MonkeyRanch * ranch; 
} 
@property (nonatomic, assign) MonkeyRanch * ranch; 
@end 

Monkey.m

@implementation Monkey 
@synthesize ranch; 
@end 

MonkeyRanch.h

#import "Monkey.h" 

@interface MonkeyRanch : NSObject { 
    NSMutableArray * monkeys; 
} 
@property (nonatomic, retain) NSMutableArray * monkeys; 
- (id)initWithNumberOfMonkeys:(int)howMany; 
- (void)dealloc; 
@end 

MonkeyRanch.m

@implementation MonkeyRanch 

@synthesize monkeys; 

- (id)initWithNumberOfMonkeys:(int)howMany { 
    if ((self = [super init]) == nil) { return nil; } 

    monkeys = [[NSMutableArray alloc] initWithCapacity:howMany]; 
    for (int index = 0; index < howMany; index++) { 
     Monkey * newMonkey = [[Monkey alloc] init]; 
     [newMonkey setRanch:self]; 
     [monkeys addObject:newMonkey]; 
     [newMonkey release]; 
    } 

    return self; 
} 

- (void)dealloc { 
    [monkeys release]; 
} 

@end 

Utilisation:

#import "MonkeyRanch.h" 

MonkeyRanch * theRanch = [[MonkeyRanch alloc] initWithNumberOfMonkeys:3]; 

... 

[theRanch release]; 
+0

Merci James! Il me manquait la valeur de la propriété et la différence de réglage de la variable membre. Et j'ai toujours voulu renvoyer la propriété au lieu de l'objet de classe lui-même. Si je devine juste je peux maintenant accéder à ma propriété de classes (le tableau de singes) comme theRanch.monkeys? (existe-t-il une solution pour ce que j'ai essayé de faire?) –

+0

Oui, vous pouvez accéder au tableau via 'theRanch.monkeys'. Vous l'avez maintenant :) mais pour être honnête, je ne suis pas sûr de ce que vous essayiez de faire. Peut-être que vous devriez poster une autre question SO sur les lignes de "Comment structureriez-vous une classe pour ce type de données?" –

1

En effet, vous manquez ceci:

theMonkeys = [[monkey alloc] initTheMonkeys:3]; 
[theMonkeys retain]; 

Lorsque vous INIT quelque chose, vous vous retrouvez avec un implicite « retenir » (l'est un chef d'accusation conserve). Il y a votre fuite; vous l'initiez tous les deux et en le conservant.

+0

Si la retenue est supprimée, les objets autorelease retournés entraînent les Monkeys jusqu'à 0 retain et le programme ... :) –

Questions connexes