2009-06-30 8 views
1

J'ai ce code:Problème avec la libération d'un objet

Entry.h

#import <Foundation/Foundation.h> 

@interface Entry : NSObject { 
    id object; 
    SEL function; 
} 

@property (retain) id object; 
@property (assign) SEL function; 

-(Entry*) initWithObject:(id)object selector:(SEL)function; 

@end 

Entry.m

#import "Entry.h" 

@implementation Entry 

@synthesize object; 
@synthesize function; 

-(Entry*) initWithObject:(id)obj selector:(SEL)sel { 
    self = [super init]; 
    [self setObject:obj]; 
    [self setFunction:sel]; 
    return self; 
} 

-(void) dealloc { 
    [super dealloc]; 
    if ([self object] != nil) 
     [[self object] release]; 
} 

@end 

Et quand je fais ceci:

Entry *hej = [Entry alloc]; 
[hej release]; 

je reçois:

objc[2504]: FREED(id): message object sent to freed object=0xf5ecd0 
Program received signal: “EXC_BAD_INSTRUCTION”. 

Qu'est-ce que je fais mal?

(Et cet insert chose de code au travail ne marche pas de débordement de pile, à moins que je fais quelque chose de mal et que vous n'êtes pas censé cliquer sur « exemple de code » puis coller.)

+1

Vous avez pas initié l'objet hej. – mkb

+0

la 'chose de code' fonctionne bien si vous collez d'abord le code dans le champ d'édition, puis sélectionnez le code que vous souhaitez marquer comme code, puis cliquez sur le bouton 'code' ... (moi confondu aussi) – kent

+0

') Les délimiteurs sont utilisés pour les polices monospace en ligne. Les échantillons de code doivent tous être indentés avec 4 espaces au début de chaque ligne, selon les règles de Markdown. J'ai corrigé le formatage de vos échantillons de code afin qu'il ne s'agisse pas d'un énorme bloc de défilement. –

Répondre

7

+alloc alloue seulement la mémoire. Vous avez besoin de -init pour créer réellement l'objet dans cet espace de mémoire. Puisque vous n'allouez que de la mémoire et que vous n'y créez pas d'objet, appeler -release sur un morceau de mémoire vous donne une erreur. En outre, vous souhaitez que votre appel [super dealloc] apparaisse à la fin de votre méthode -dealloc. Changer ces deux choses et ce qui suit devrait fonctionner:

Entry *hej = [[Entry alloc] init]; 
[hej release]; 
+1

Le dernier problème potentiel (que vous verrez rarement en pratique, mais en le codant pour "la bonne chose") est de vérifier le soi pour rien, comme le souligne @Kent. Utilisez ceci autour de votre code: if ((self = [super init])! = Nil) {...} –

1

Premièrement, vous avez besoin d'un init pour aller avec votre alloc. Deuxièmement, dans dealloc, vous envoyez un message à vous-même après avoir appelé [super dealloc]. Tu ne peux pas faire ça. La désallocation finale devrait aller à la fin.

+0

que fait exactement dealloc? Pourquoi se soucie-t-il si l'objet est initialisé ou non? Pourquoi ne pas simplement libérer la mémoire allouée? – quano

+0

Il libère la mémoire. Dealloc détruit l'objet et libère la mémoire utilisée pour le contenir. Vous ne pouvez donc plus envoyer d'objet à l'objet car il n'existe plus. – Chuck

+0

Où puis-je trouver la source du dealloc original? Je veux voir ce que ça fait. – quano

3

il y a deux problèmes ici:

1) vous devez vérifier que self = [super init] ne retourne pas nul. L'usage typique serait de suivre enveloppez votre code d'initialisation avec le conditionnel:

if ((self = [super init]) != nil) { 
    // initialize the object... 
} 

2) mais où vous rester coincé est sur instancier votre objet: vous devriez le faire comme ceci:

Entry *hej = [[Entry alloc] initWithObject:myObj selector:mySelector]; 

(en supposant que vous voulez passer par l'initialiseur personnalisé que vous venez de définir ... sinon utilisez simplement la méthode init par défaut.) mais 'alloc' doit être suivi d'un init.

Entry *hej = [[Entry alloc] init]; // will do the trick... 
+1

chuck a également raison de souligner que votre méthode dealloc devrait appeler [super dealloc] comme la dernière chose avant de quitter ... (donc trois problèmes dans toto) – kent

1

Je recommande également de changer:

if ([self object] != nil) 
    [[self object] release]; 

à:

[self setObject:nil]; 

Il est moins de code et fonctionnellement équivalent. =)

+0

Mais l'objet n'existera-t-il pas encore si vous le faites? – quano

+2

@quano: Non, parce que ça passe par votre accesseur synthétisé. Puisque la propriété est déclarée retenue, l'accesseur libère l'ancienne valeur lorsque vous en définissez une nouvelle. C'est juste comme quand vous appelez [self setObject: quelque chose], vous n'avez pas besoin de libérer explicitement l'ancienne valeur. – Chuck

+0

qui a du sens. J'ai aussi vu que vous pouvez juste faire [[self object] release], parce que c'est correct d'envoyer des messages à des objets nuls. – quano

0

Il y a beaucoup de problèmes avec votre code. Je vais essayer de les traverser. Tout d'abord, il est préférable d'utiliser un autre nom ivar pour votre nom de propriété afin de savoir où vous utilisez chacun. Apple utilise normalement un préfixe de soulignement, mais n'importe quel préfixe fera l'affaire.

@interface Entry : NSObject { 
    id _object; 
    SEL _function; 
} 

@property (retain) id object; 
@property (assign) SEL function; 

@synthesize object = _object; 
@synthesize function = _function; 

Ensuite, vous n'utilisez pas le modèle standard init (bien que cela ne sera probablement pas faire une différence normalement).

-(Entry*) initWithObject:(id)obj selector:(SEL)sel { 
    self = [super init]; 
if (self != nil) { 
    // initializations 
} 
    return self; 
} 

Ensuite, Apple (pour de bonnes raisons) recommande de ne pas utiliser getters/setters dans votre init/dealloc. Alors init serait:

-(Entry*) initWithObject:(id)obj selector:(SEL)sel { 
    self = [super init]; 
if (self != nil) { 
    _object = [obj retain]; 
    _object = sel; 
} 
    return self; 
} 

Ensuite, après [super dealloc] votre objet est détruit, de sorte que vous ne pouvez pas faire référence à soi-même (et donc vos Ivars) après cela, de sorte que votre dealloc devrait ressembler à:

-(void) dealloc { 
    // your deallocations 
    [super dealloc]; 
} 

en outre, comme ci-dessus, Apple vous recommande ne devriez pas utiliser setters ou accesseurs dans votre routine dealloc, de sorte que votre désallocation regarderaient d'abord comme:

if (_object != nil) 
    [_object release]; 

Mais plus loin encore, l'objet ive C permet (et Cocoa encourage) que l'envoi d'une méthode à zéro ne fait rien. Ceci est en contradiction flagrante avec la plupart des autres langages dans lesquels la messagerie nil causerait un plantage, mais c'est ainsi que fonctionne Objective C/Cocoa et que vous devez vous y habituer. Donc, votre désallocation est en fait juste:

Et enfin, alloc alloue seulement la mémoire de votre objet, vous devez l'initialiser, de sorte que l'initialisation serait quelque chose comme:

Entry *hej = [[Entry alloc] initWithObject:myobj selector:@selector(mymethod)]; 
+0

Merci peter. :) – quano

Questions connexes