Problème NSDate

RocouRocou Membre
02:46 modifié dans API AppKit #1
Mon programme plante sans que je comprenne pourquoi. J'y suis depuis midi et je commence à  désespérer

Voici mon code (simplifié):

- (id)initWithFrame:(NSRect)rect {<br />&nbsp; &nbsp; self = [super initWithFrame:rect];<br />&nbsp; &nbsp; if (self) <br />	{<br />		<br />		//préparation du tracé du calendrier<br />		//___________________________________<br />		<br />		NSRect bounds = [self bounds]; <br />		largeurColonneDefaut=90;	<br />		nbColonnesAffichees = 50; //pour être sûr de dépasser la largeur d&#39;un écran.<br />		NSDate *ladate = [NSDate date];<br />		NSTimeInterval secondsPerDay = 24 * 60 * 60;<br />		<br />			<br />		coul = [NSColor blackColor];<br />		ColArray = [[NSMutableArray alloc] initWithCapacity:(nbColonnesAffichees)];<br />		<br />		x=0;<br />		y=0;<br />		for(int i =0; i&lt;nbColonnesAffichees; i++)<br />		{<br />			Calendrier *uneColonne = [[Calendrier alloc]init];<br />			[uneColonne initWithPosX:x PosY:y TWidth:largeurColonneDefaut THeight:bounds.size.height withColor:coul andSelect:NO];<br />			<br />			//l&#39;entete<br />			[uneColonne initLigneEntete:x PosY:y TWidth:largeurColonneDefaut THeight:20 withColor:coul withDate:ladate];<br />			//On incrémente la date<br />			ladate = [ladate addTimeInterval:secondsPerDay];<br />					<br />			[ColArray addObject:uneColonne];<br /><br />			<br />			x = largeurColonneDefaut + i * largeurColonneDefaut;<br />			[uneColonne release];<br />		}<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return self;<br />}<br />


Ce qui est important: j'initialise une zone avec une NSDate. A priori, ça fonctionne très bien.
Et maintenant, l'affichage:

NSDateFormatter *dateFormatter;<br />...<br /><br />- (void)drawRect:(NSRect)rect {<br />	<br />	<br />	NSRect bounds = [self bounds];<br />	<br />	NSString *maDate=@&quot;&quot;;<br />	<br />	int i;<br />	//On dessine le calendrier<br />	CGFloat hauteurColonne = bounds.size.height;<br />	<br />	for(i =0;i&lt;nbColonnesAffichees;i++)<br />	{<br />	<br />		// objet va recevoir les informations de chaque location <br />		Calendrier *uneColonne = [ColArray objectAtIndex:i];<br />		<br />		// on dessine un rectangle grâce au informations détenu par uneLocation <br />		NSRect laColonne = NSMakeRect([uneColonne abs_value], [uneColonne ord_value], [uneColonne largeur_value],hauteurColonne);<br />		<br />	&nbsp; &nbsp; // chaque rectangle existant (chaque colonne) est dessiné						<br />		[[NSColor whiteColor] set];<br />		NSRectFill(laColonne);<br />		[[NSColor blackColor] set];<br />		NSFrameRectWithWidth ( laColonne, 0.1 ); 	<br />				<br />		//On dessine la ligne d&#39;entête (qui est en fait une succession de rectangle d&#39;entête)<br />		Calendrier *uneEntete = [ColArray objectAtIndex:i];<br />		<br />		// on dessine un rectangle grâce aux informations détenues par uneEntete <br />		NSRect lEntete = NSMakeRect([uneEntete x_entete_value], [uneEntete y_entete_value], [uneEntete largeur_entete_value],[uneEntete hauteur_entete_value]);<br />		[[NSColor lightGrayColor] set];<br />		NSRectFill(lEntete);<br />		[[NSColor blackColor] set];<br />		NSFrameRectWithWidth ( lEntete, 0.1 ); 	<br />		<br />		<br /><br />		//Le texte des entetes<br />		dateFormatter =[[[NSDateFormatter alloc] init]&nbsp; autorelease];<br />		[dateFormatter setDateStyle:NSDateFormatterShortStyle];<br />		[dateFormatter setTimeStyle:NSDateFormatterNoStyle];<br />		maDate = [dateFormatter stringFromDate:uneEntete.date_entete];<br />		<br />		<br />		[maDate drawAtPoint:NSMakePoint([uneEntete abs_value]+((lEntete.size.width - 40)/2),[uneEntete ord_value]+2) withAttributes:nil];<br />	<br />		}<br />		<br />}<br />


ça fonctionne très bien... Une seule fois. Quand drawRect est appelé une nouvelle fois, le programme plante. C'est à  l'utilisation de "maDate" que le programme plante. En face de "maDate", le debugger indique invalid.
:why?:

Réponses

  • tabliertablier Membre
    02:46 modifié #2
      :o Il me semble: les NSDate ne sont pas des objets mutables. Tu peux les créer, les détruire, mais pas les modifier!!
  • RocouRocou Membre
    02:46 modifié #3
    dans 1243027638:

      :o Il me semble: les NSDate ne sont pas des objets mutables. Tu peux les créer, les détruire, mais pas les modifier!!

    Merci Tablier. Cependant, je n'ai pas l'impression de les modifier. Elles sont créées dans le initFrame puis elles sont lues.

    Dans initFrame j'ai bien:
    ladate = [ladate addTimeInterval:secondsPerDay]; qui ne semble pas correct mais même en supprimant cette ligne, le problème reste le même.
  • NseaProtectorNseaProtector Membre
    02:46 modifié #4
    NSString *maDate=@";";

    Essaye de déclarer un NSMutableString en dehors de drawRect, avec alloc / init ...
    et son release en Dealloc.
  • RocouRocou Membre
    02:46 modifié #5
    dans 1243050880:

    NSString *maDate=@";";

    Essaye de déclarer un NSMutableString en dehors de drawRect, avec alloc / init ...
    et son release en Dealloc.

    Merci mais ça plante de la même façon  :'(
  • NseaProtectorNseaProtector Membre
    02:46 modifié #6
    Joins ton source simplifié que l'on puisse voir ...
  • RocouRocou Membre
    02:46 modifié #7
    dans 1243074369:

    Joins ton source simplifié que l'on puisse voir ...

    Merci, le voici:

    http://dl.free.fr/ujqFjpKhH

  • NseaProtectorNseaProtector Membre
    02:46 modifié #8
    Déja le problème vient du dateFormatter, si tu mets une dâte fixe genre
    @01/01/09 à  la place et bien ça plante plus...

    [maDate setString: [dateFormatter stringFromDate:uneEntete.date_entete]];
  • RocouRocou Membre
    02:46 modifié #9
    dans 1243087277:

    Déja le problème vient du dateFormatter, si tu mets une dâte fixe genre
    @01/01/09 à  la place et bien ça plante plus...

    Oui, c'est ce que je disais au début du fil. Je peux mettre directement des chaà®nes, des nombres, ça ne plante pas.

    Mais comment convertir une NSDate en string sans dateFormatter?
    J'ai bien essayé ceci: maDate = [NSString stringWithFormat:@%d,uneEntete.date_entete];
    mais ça plante tout autant.
  • NseaProtectorNseaProtector Membre
    mai 2009 modifié #10
    En faite ton soucis viens de l'allocation de dateFormatter. Mets l'allocation dans la methode init sans l'appel d'autorelease et sans oublier de rajouter dateFormatter aux objets dans dealloc.
    D'ailleurs ça m'a l'air d'être un beau sac de noeuds, je ne comprends pas tes allocations dans la fonction drawRect, je ne suis assez sûr de moi pour te conseiller, mais il me semble que le model MVC n'est pas respecté.
    Au redraw, dateFormater plante parce qu'il va cherché dans un tableau vide, (que tu viens juste d'alloué)...
  • RocouRocou Membre
    02:46 modifié #11
    dans 1243088253:

    En faite ton soucis viens de l'allocation de dateFormatter. Mets l'allocation dans la methode init sans l'appel d'autorelease et sans oublier de rajouter dateFormatter aux objets dans dealloc.
    D'ailleurs ça m'a l'air d'être un beau sac de noeuds, je ne comprends pas tes allocations dans la fonction drawRect, je ne suis assez sûr de moi pour te conseiller, mais il me semble que le model MVC n'est pas respecté.
    Au redraw, dateFormater plante parce qu'il va cherché dans un tableau vide, (que tu viens juste d'alloué)...

    Qu'est-ce que tu ne comprends pas?
    Ce genre de ligne?:
    Calendrier *uneEntete = [ColArray objectAtIndex:i];

    Je créée une instance de Calendrier que j'initialise avec le contenu d'une case d'un tableau d'objets (des instances de Calendrier).

    J'ai grandement pompé sur un source de ceetix, peut-être ai-je mal adapté son code, je suis en train de tester des choses (le graphisme) que je n'avais jamais abordé.

    Cela dit, j'ai testé ton idée concernant le dateFormatter mais ça plante toujours  :(
    mon tableau ColArray se viderait entre deux appels de drawRect?
    Ce qui m'ennuie le plus, c'est que je n'ai pas d'idée pour contourner ce problème insoluble (pour moi).
  • NseaProtectorNseaProtector Membre
    02:46 modifié #12
    Ben oui c'est ton instance de calendrier dans le drawRect qui me gène, normalement ça fait partis du model, pas de la vue.
    Le redessin doit prendre les infos dans le model mais pas créer une nouvelle instance.
    Si tu place un breakpoint sur [maDate setString: [dateFormatter stringFromDate:uneEntete.date_entete]];
    Tu pourras remarquer qu'au redraw ton tableau uneEntete est vide et c'est ça qui plante cette ligne.
  • RocouRocou Membre
    02:46 modifié #13
    dans 1243098825:

    Ben oui c'est ton instance de calendrier dans le drawRect qui me gène, normalement ça fait partis du model, pas de la vue.
    Le redessin doit prendre les infos dans le model mais pas créer une nouvelle instance.

    Je comprends ce que tu veux dire mais même si je ne crée aucune instance et que j'utilise directement [ColArray objectAtIndex:i], ça plante tout autant.

    J'ai trouvé un "tourne-autour" afin d'avancer en générant directement mes date dans le drawRect mais ça m'oblige à  revoir l'analyse de mon projet et surtout j'aimerais bien comprendre pourquoi mon tableau se vide entre deux appels à  drawRect (et pas tout le tableau car les coordonnées des rectangles que je dessine, qui sont des données du même tableau, sont toujours présentes...)

    Merci beaucoup pour le temps passé. Si tu as une autre idée, je suis preneur!
  • mpergandmpergand Membre
    mai 2009 modifié #14
    dans 1243096496:

    Cela dit, j'ai testé ton idée concernant le dateFormatter mais ça plante toujours  :(
    mon tableau ColArray se viderait entre deux appels de drawRect?
    Ce qui m'ennuie le plus, c'est que je n'ai pas d'idée pour contourner ce problème insoluble (pour moi).


    uneEntete.date_entete est invalid car releasé  ;)

    Bon, ton code c'est  :o

    C'est quoi ces variables globales ?

    NSInteger largeurColonneDefaut;
    NSDateFormatter *dateFormatter;
    NSMutableString *maDate=@";";

    et
    maDate = [[NSMutableString alloc]init];
    ne sert à  rien...
    Et on initialise les variables d'instance dans init !

    Ca plante à  cause de ça (pas de retain):
    largeur_entete = w;
    hauteur_entete = h;
    couleur_entete = c;

    Potasse bien la gestion mémoire car tu ne va pas t'en sortir sinon...
    Enfin, je te conseillerais de ne pas utiliser les property et de tout gérer à  la main, pour bien comprendre comment fonctionne la gestion mémoire dans les accesseurs.

    [EDIT]

    une méthode init ce fait comme ça:
    - (void)initLigneEntete:(CGFloat)x PosY:(CGFloat)y TWidth:(CGFloat )w THeight:(CGFloat)h withColor:(NSColor *)c withDate:(NSDate *)d <br />{<br />	if(self=[super init])<br />		{<br />	<br />		x_entete = x;<br />		y_entete = y;<br />		largeur_entete = w;<br />		hauteur_entete = h;<br />		self.couleur_entete = c;<br />		self.date_entete = d;<br />		}<br />	<br />	return self;<br /><br />}<br /><br />-(void)dealloc<br />{<br />	[couleur_entete release];<br />	[date_entete release];<br />	[super dealloc];<br />}<br />
    

    Ca devrait aller mieux, pas tester car je n'utilise pas Xcode 3  ;)
  • RocouRocou Membre
    02:46 modifié #15
    dans 1243102878:

    uneEntete.date_entete est invalid car releasé  ;)

    D'accord mais en faisant directement appel au tableau colArray, je devrais retrouver mes infos, non?
    Et pourquoi uneEntete.x_entete (par exemple) n'est pas releasé?
    dans 1243102878:

    Bon, ton code c'est  :o

    C'est quoi ces variables globales ?

    NSInteger largeurColonneDefaut;
    NSDateFormatter *dateFormatter;
    NSMutableString *maDate=@";";


    et
    maDate = [[NSMutableString alloc]init];
    ne sert à  rien...
    Et on initialise les variables d'instance dans init !

    Tout ceci vient de mes innombrables tests. A l'origine, c'était plus propre  :)

    dans 1243102878:

    Ca plante à  cause de ça (pas de retain):
    largeur_entete = w;
    hauteur_entete = h;
    couleur_entete = c;

    Potasse bien la gestion mémoire car tu ne va pas t'en sortir sinon...
    Enfin, je te conseillerais de ne pas utiliser les property et de tout gérer à  la main, pour bien comprendre comment fonctionne la gestion mémoire dans les accesseurs.

    En effet, je ne comprends pas grand chose à  cette satanée gestion de la mémoire.
    Où dois-je mettre mon retain? J'ai tenté d'en mettre à  chacune de mes allocations, juste pour voir, ça plante toujours au même endroit.
  • RocouRocou Membre
    mai 2009 modifié #16
    dans 1243102878:

    une méthode init ce fait comme ça:
    - (void)initLigneEntete:(CGFloat)x PosY:(CGFloat)y TWidth:(CGFloat )w THeight:(CGFloat)h withColor:(NSColor *)c withDate:(NSDate *)d <br />{<br />	if(self=[super init])<br />		{<br />	<br />		x_entete = x;<br />		y_entete = y;<br />		largeur_entete = w;<br />		hauteur_entete = h;<br />		self.couleur_entete = c;<br />		self.date_entete = d;<br />		}<br />	<br />	return self;<br /><br />}<br /><br />-(void)dealloc<br />{<br />	[couleur_entete release];<br />	[date_entete release];<br />	[super dealloc];<br />}<br />
    

    Ca devrait aller mieux, pas tester car je n'utilise pas Xcode 3  ;)

    Bon, ça ne passe pas du tout à  la compilation (return avec void? self.couleur_entête??)
    Je vais bosser l'idée.
  • mpergandmpergand Membre
    02:46 modifié #17
    Oui, faut refaire l'init proprement  ;)
    Calendrier *uneColonne = [[Calendrier alloc]init];<br />			[uneColonne initWithPosX:x PosY:y TWidth:largeurColonneDefaut THeight:bounds.size.height withColor:coul andSelect:NO];<br />			<br />			//l&#39;entete<br />			[uneColonne initLigneEntete:x PosY:y TWidth:largeurColonneDefaut THeight:20 withColor:coul withDate:ladate];
    


    Curieux ! pas de params en init et deux init derrières, plus pas de retain sur les objets et pas de dealloc non plus !

    Enfin, tu n'as pas d'objet Controller dans ton projet et c'est pour ça que ton code est un vrai bazar ...
  • RocouRocou Membre
    02:46 modifié #18
    dans 1243107148:

    Oui, faut refaire l'init proprement  ;)
    Calendrier *uneColonne = [[Calendrier alloc]init];<br />			[uneColonne initWithPosX:x PosY:y TWidth:largeurColonneDefaut THeight:bounds.size.height withColor:coul andSelect:NO];<br />			<br />			//l&#39;entete<br />			[uneColonne initLigneEntete:x PosY:y TWidth:largeurColonneDefaut THeight:20 withColor:coul withDate:ladate];
    


    Curieux ! pas de params en init et deux init derrières, plus pas de retain sur les objets et pas de dealloc non plus !

    Oui, j'aurais pu faire tout dans un seul init mais bon, ce n'est pas ça qui fait planter mon code. J'ai voulu tester à  la va vite les fonctions graphiques.
    J'ai ajouté des retain, cela ne change rien. Par contre, j'ai bien des release (cf la fin de la boucle for())

    dans 1243107148:

    Enfin, tu n'as pas d'objet Controller dans ton projet et c'est pour ça que ton code est un vrai bazar ...

    Bah si, mon contrôleur s'appelle MonPlanning.
  • mpergandmpergand Membre
    02:46 modifié #19
    Bah si, mon contrôleur s'appelle MonPlanning.


    @interface MonPlanning : NSView
    ::)



  • RocouRocou Membre
    02:46 modifié #20
    dans 1243113877:

    Bah si, mon contrôleur s'appelle MonPlanning.


    @interface MonPlanning : NSView
    ::)

    En quoi n'est-ce pas bon?
  • AliGatorAliGator Membre, Modérateur
    02:46 modifié #21
    Bah s'il hérite de NSView, c'est pas une classe jouant le rôle de contrôleur, mais une classe jouant le rôle de vue... Donc c'est loin d'être conforme au paradigme/design pattern M-V-C...
  • RocouRocou Membre
    02:46 modifié #22
    dans 1243128920:

    Bah s'il hérite de NSView, c'est pas une classe jouant le rôle de contrôleur, mais une classe jouant le rôle de vue... Donc c'est loin d'être conforme au paradigme/design pattern M-V-C...

    Ha ok. Merci. Bon je vais tout réécrire.
  • mpergandmpergand Membre
    02:46 modifié #23
    dans 1243154774:

    dans 1243128920:

    Bah s'il hérite de NSView, c'est pas une classe jouant le rôle de contrôleur, mais une classe jouant le rôle de vue... Donc c'est loin d'être conforme au paradigme/design pattern M-V-C...

    Ha ok. Merci. Bon je vais tout réécrire.


    Sage résolution  ;)

    Et je commencerais par définir la classe modèle (données), ce que tu n'as même pas fait !

    Par ex :

    class Location
    {
      NomLocation,
      NomLocataire,
      DateDébut,
      DateFin
    }

    puis le nom des locations (un simple tableau ?)

    { Trifouilli les oies, Perpette les bains}

    Implémenter le NSCoding pour la sauvegarde.


    Toutes ces classes n'ont pas d'informations de positions, c'est le problème de la vue.
    C'est le Controlleur qui fournira à  la vue (Planning) les données à  afficher.

    MVC powa  :)


  • RocouRocou Membre
    02:46 modifié #24
    dans 1243160921:

    Et je commencerais par définir la classe modèle (données), ce que tu n'as même pas fait !

    Par ex :

    class Location
    {
      NomLocation,
      NomLocataire,
      DateDébut,
      DateFin
    }

    L'analyse est faite et je ne crois pas être trop mauvais dans ce domaine  :)
    Le code que tu as pu voir est écrit uniquement pour découvrir comment fonctionne le graphisme.

    dans 1243160921:

    Implémenter le NSCoding pour la sauvegarde.


    Inutile, tout est stocké dans une base de donnéees PostgreSQL

    dans 1243160921:

    Toutes ces classes n'ont pas d'informations de positions, c'est le problème de la vue.
    C'est le Controlleur qui fournira à  la vue (Planning) les données à  afficher.

    MVC powa  :)

    Ha oui, je comprends, j'ai effectivement fait n'importe quoi  :)

    Merci!
  • NseaProtectorNseaProtector Membre
    mai 2009 modifié #25
    Juste une approche différente de la tienne.
    Pour les événements, il suffit de créer un tableau mutable et dessiner les éléments en comparant la date dans la boucle de dessin.
    C'est très perfectible mais ça peut te donner des idées pour avancer...
    Edit: En fait il manque le modèle, l'appController devrait changer la date de début dans le modèle...
Connectez-vous ou Inscrivez-vous pour répondre.