Pourquoi mon programme plante !!??
zenx
Membre
J'avais déjà posé un message similaire sur la question que je souhaite aborder ici. Si je me permets de revenir sur le sujet, c'est parce que je n'ai toujours pas compris l'interêt du [date retain] dans le listing que je vous présente ci-dessous. En effet, lorsque je le supprime, le programme plante à la fin de l'éxecution. Voyez plutôt :
ParticipationLoterie.m
#import "ParticipationLoterie.h"
@implementation ParticipationLoterie
- (void)setNumbersRandomly {
firstNumber = random() % 100 + 1;
secondNumber= random() % 100 + 1;
}
- (void)setEntryDate: (NSCalendarDate *) date {
[date retain];
[entryDate release];
[date setCalendarFormat: @%d %b %y];
entryDate = date;
}
- (NSCalendarDate *) entryDate{
return entryDate;
}
- (int)firstNumber {
return firstNumber;
}
- (int)secondNumber {
return secondNumber;
}
- (void)dealloc {
NSLog(@Destruction %@",self);
[entryDate release];
[super dealloc];
}
- (NSString *)description{
return [NSString stringWithFormat: @%@ = %d et %d",entryDate,firstNumber,secondNumber];
}
@end
main.m
#import <Foundation/Foundation.h>
#import "ParticipationLoterie.h"
int main (int argc, const char * argv[]) {
NSMutableArray *array;
int i;
ParticipationLoterie *entry;
NSCalendarDate *now;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
now = [[NSCalendarDate alloc] init];
srandom(time(NULL));
array = [[NSMutableArray alloc] init];
for (i=0;i<10;i++){
entry = ParticipationLoterie alloc] init];<br /> [entry setNumbersRandomly];<br /> [color=blue][b][entry [color=orange]setEntryDate[/color]: [now dateByAddingYears: 0 months:0 days:(i*7) hours:0 minutes:0 seconds:0;[/b][/color]
[array addObject:entry];
[entry release];
}
NSLog(@Array = %@",[array description]);
[array release];
[now release];
[pool release];
return 0;
}
Qu'en pensez vous ?
ParticipationLoterie.m
#import "ParticipationLoterie.h"
@implementation ParticipationLoterie
- (void)setNumbersRandomly {
firstNumber = random() % 100 + 1;
secondNumber= random() % 100 + 1;
}
- (void)setEntryDate: (NSCalendarDate *) date {
[date retain];
[entryDate release];
[date setCalendarFormat: @%d %b %y];
entryDate = date;
}
- (NSCalendarDate *) entryDate{
return entryDate;
}
- (int)firstNumber {
return firstNumber;
}
- (int)secondNumber {
return secondNumber;
}
- (void)dealloc {
NSLog(@Destruction %@",self);
[entryDate release];
[super dealloc];
}
- (NSString *)description{
return [NSString stringWithFormat: @%@ = %d et %d",entryDate,firstNumber,secondNumber];
}
@end
main.m
#import <Foundation/Foundation.h>
#import "ParticipationLoterie.h"
int main (int argc, const char * argv[]) {
NSMutableArray *array;
int i;
ParticipationLoterie *entry;
NSCalendarDate *now;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
now = [[NSCalendarDate alloc] init];
srandom(time(NULL));
array = [[NSMutableArray alloc] init];
for (i=0;i<10;i++){
entry = ParticipationLoterie alloc] init];<br /> [entry setNumbersRandomly];<br /> [color=blue][b][entry [color=orange]setEntryDate[/color]: [now dateByAddingYears: 0 months:0 days:(i*7) hours:0 minutes:0 seconds:0;[/b][/color]
[array addObject:entry];
[entry release];
}
NSLog(@Array = %@",[array description]);
[array release];
[now release];
[pool release];
return 0;
}
Qu'en pensez vous ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Moi perso je n'ai jamais touché au fichier main.m qui, pour moi, doit rester en l'état.
Si tu as des initialisations à faire, il faut les faire dans le awakeFromNib pour un objet instancié dans IB (un contrôlleur par exemple, ou une NSView personnalisée que tu auras mis dans IB avec un outlet pointant sur elle, etc), ou dans le init ou initWithCoder pour des objets autres, et tout ce genre.
----
Sinon pour l'histoire de ton retain, lis l'article de Renaud il te sera très enrichissant. Pour faire bref, dans ton cas précis, peut-être que ce remaniement de code (qui n'est pas correct, tu comprendras la subtilité dans un 2e temps, mais qui est une étape intermédiaire pour comprendre) t'aidera à capter ?
Le principe de base : les objets sont mis dans une zone de la mémoire, et les variables pointent sur ces zones mémoire. 2 variables peuvent pointer sur exactement le même objet, et changer l'objet par l'intermédiaire d'une variable fera que si tu accèdes à ce même objet par l'autre variable ses propriétés auront changé aussi (puisque c'est le même objet).
Maintenant, à chaque fois que tu as une variable qui pointe sur un objet, il faut que tu fasses un retain dessus pour déclarer qu'il y a une variable de plus qui a "besoin" de cet objet. et un "release" à chaque fois que tu n'as plus besoin de ta variable pour dire. Quand le retainCount atteint zéro c'est que plus aucune variable n'a besoin de (ou pointe vers) l'objet, donc que l'objet ne sert plus à rien, il est alors libéré de la mémoire.
----
Bon j'en ai déjà trop dit puisque tout ça est repris dans le tuto de Renaud.
Quant à la petite subtilité, c'est qu'en réalité il faut dans ce genre de cas (cas classique de remplacement de la valeur d'une variable d'instance avec une méthode setXXX, elles sont typiquement toutes la même tête) toujours faire le [parametre retain] avant le [variable_d_instance release] et non pas l'inverse au cas où la variable d'instance et le paramètre pointeraient déjà exactement sur le même objet. M'enfin tu comprendras cette subtilité quand tu maà®triseras + la gestion de la mémoire
La méthode dateByAddingYears:months:days:hours:minutes:seconds: que tu appliques à ton objet NSCalendarDate now renvoie un nouvel objet NSCalendarDate qui est le résultat de l'addition de now avec les paramètres de la méthode.
Ce nouvel objet NSCalendarDate n'a pas été crée par toi via alloc, donc, il s'agit d'un objet autoreleasable. Il est donc créé avec un compteur de référence valant 1, puis est mis dans l'autorelease-pool.
Par la suite, tu fais un [tt][array release];[/tt] pour détruire le tableau contenant les entry. On peut donc supposer que chaque entry est supprimé : la méthode dealloc de la classe PartcipationLoterie est donc appellée.
Dans dealloc, tu releases la date qui avait été précédemment récupérée du nouvel objet NSCalendarDate.
Donc, le compteur de référence de ce nouvel objet passe de 1 à 0, ce qui a pour effet de détruire ce nouvel objet.
Enfin, tu fais un [tt][pool release];[/tt]. En faisant cela, chaque objet contenu dans l'autorelease-pool reçoit un release.
Comme, le nouvel objet NSCalendarDate était dans l'autorelease-pool, il reçoit son release. Mais ça ne peut que planter, puisque ce nouvel objet a été précédemment détruit.
.