Problème de fenêtres

TchouboudouTchouboudou Membre
août 2007 modifié dans API AppKit #1
Bonjour les gens

Dans mon application, j'ai un array. Je dois créer des fenêtres en fonction de [array count]. Je fais une enumeration et j'appelle une fonction : voici cette fonction :

- (void)createStickyWithString:(NSDictionary *)dictionary<br />{<br />	[notesShowed addObject:[dictionary retain]];<br />	<br />&nbsp; &nbsp; &nbsp; &nbsp; Stickies *newSticky = [[Stickies alloc] initWithContentRect:NSMakeRect(300, 400, 225, 206)<br />											styleMask:NSBorderlessWindowMask<br />											backing:NSBackingStoreBuffered<br />											defer:NO];<br />	<br />	NSView *mainView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 225, 206)];<br />	<br />	NSImageView *stickyImageView = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, 225, 206)];<br />	[stickyImageView setImage:[NSImage imageNamed:@&quot;Sticky&quot;]];<br />	[mainView addSubview:stickyImageView];<br />	<br />	NSButton *closeButton = [[NSButton alloc] initWithFrame:NSMakeRect(14, 181, 19, 19)];<br />	[closeButton setBezelStyle:NSRoundedBezelStyle];<br />	[closeButton setButtonType:NSToggleButton];<br />	[closeButton setImagePosition:NSImageOnly];<br />	[closeButton setImage:[NSImage imageNamed:@&quot;close&quot;]];<br />	[closeButton setBordered:NO];<br />	[mainView addSubview:closeButton];<br />	<br />	NSTextField *field = [[NSTextField alloc] initWithFrame:NSMakeRect(14, 31, 191, 155)];<br />	[field setEditable:NO];<br />	[field setBordered:NO];<br />	[field setDrawsBackground:NO];<br />	[field setFont:[NSFont fontWithName:@&quot;Marker Felt&quot; size:14]];<br />	[field setStringValue:[dictionary objectForKey:@&quot;String&quot;]];<br />	[mainView addSubview:field];<br />	<br />	[newSticky setContentView:mainView];<br />	<br />	[newSticky makeKeyAndOrderFront:nil];<br />	<br />	[notes removeObject:dictionary];<br />}


Il y a une merde (ou plusieurs) au niveau de la mémoire. Les fenêtres s'affichent, mais je ne peux pas les bouger (alors que s'il n'y en a qu'une, je ppeux la déplacer).

Avez-vous LA solution miracle :) .

Merci d'avance,
Tchouboudou

Réponses

  • 23:35 modifié #2
    Il y a plusieurs moyens de faire. Mais pour moi le plus simple est que tu crées une classe controller pour les fenêtres. Dans le init de cette classe controller, tu charges un nib (dont il est le file owner - ([tt]+[NSBundle loadNibNamed:owner][/tt] et comme owner tu mets self).

    Puis tu peux parcourir ton tableau et créer une instance de ta classe controller par élément dans ton tableau (n'oublie pas de stocker les controller quelque part pour les relâcher quand tu n'en auras plus besoin).

    Il y a encore d'autres façons de faire.
  • schlumschlum Membre
    août 2007 modifié #3
    T'essaies de faire un truc à  la sauce Java en construisant ta fenêtre avec du code...

    Il manque trop de code pour voir ce qui cloche : qu'est-ce que Stickie par exemple ?

    Comme dit Renaud, les .nib sont fait pour ce genre de choses !

    Crée au moins la "contentView" dedans :D
  • Eddy58Eddy58 Membre
    23:35 modifié #4
    La solution exposée par Renaud est la plus simple et élégante, je voudrais juste te faire remarquer que ton code plus haut génère des fuites mémoires.

    <br />	[notesShowed addObject:[dictionary retain]]; -&gt; [notesShowed addObject:dictionary];<br />
    

    Le retain est inutile ici, tu ajoutes le dictionary dans un array, ceux-ci effectuent le retain en interne.

    <br />	NSImageView *stickyImageView = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, 225, 206)];<br />	[stickyImageView setImage:[NSImage imageNamed:@&quot;Sticky&quot;]];<br />	[mainView addSubview:stickyImageView];<br />&nbsp; &nbsp; &nbsp; &nbsp; [stickyImageView release]; // &lt;===========<br />
    


    <br />	[newSticky setContentView:mainView];<br />&nbsp; &nbsp; &nbsp;  [mainView release]; // &lt;===========<br />
    

    N'oublies pas le release une fois que tu n'as plus besoin de ton objet, c'est valable pour tout le code au-dessous aussi. ;)
  • TchouboudouTchouboudou Membre
    23:35 modifié #5
    J'ai fait comme l'a dit Renaud, j'ai créé une sous-classe de NSWindowController.

    schlum : Stickies est une sous-classe de NSWindow, elle me permet juste de faire quelques réglages (setOpaque, setHasShadow, etc).

    Si vous me permettez, j'aimerais vous poser une question sur la mémoire. Dans ma fonction init, j'initialise un array, et je crée ensuite un dictionnaire que j'ajoute dans l'array. Je "release" le dictionnaire.
    Dans une autre fonction, je supprime le dictionnaire. Et, d'un coup la fenêtre de debug s'affiche.
    Cela doit être sûrement un problème de mémoire, mais comment le régler ?
  • Eddy58Eddy58 Membre
    23:35 modifié #6
    dans 1186405080:

    Si vous me permettez, j'aimerais vous poser une question sur la mémoire. Dans ma fonction init, j'initialise un array, et je crée ensuite un dictionnaire que j'ajoute dans l'array. Je "release" le dictionnaire.
    Dans une autre fonction, je supprime le dictionnaire. Et, d'un coup la fenêtre de debug s'affiche.
    Cela doit être sûrement un problème de mémoire, mais comment le régler ?

    Dans ce cas il ne faut pas releaser ton dictionnaire après l'avoir ajouté dans l'array, mais dans ta fonction de suppression.
  • TchouboudouTchouboudou Membre
    23:35 modifié #7
    Le dictionaire est toujours dans le tableau...
  • Eddy58Eddy58 Membre
    23:35 modifié #8
    Sois plus claire, un peu plus de code ça ferait pas de mal non plus...
    Ca plante quand tu veux supprimer le dictionnaire de ton array ?
  • TchouboudouTchouboudou Membre
    août 2007 modifié #9
    Excusez-moi pour le manque de code.
    Initialisation :

    notes = [[NSMutableArray alloc] init];<br />		<br />NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];<br />[dic setObject:@&quot;Bp&quot; forKey:@&quot;String&quot;];<br />		<br />NSCalendarDate *date = [NSCalendarDate dateWithYear:2006<br />					month:8<br />					day:6<br />					hour:14<br />					minute:42<br />					second:0<br />					timeZone:[NSTimeZone defaultTimeZone]];<br />		<br />[dic setObject:date forKey:@&quot;Date&quot;];<br />[notes addObject:dic];
    


    Et pour la suppression

    [notes removeObjectAtIndex:i]
    


    Sinon, la suppression se fait bien, c'est après que ça bug, mais si je fais pas la suppression, ça marche impec'.

    Euh, peut-être il faut que je précise que la suppression se fait dans une énumération qui se fait tous les 10 secondes (NSTimer) ?

    Voili, voilou...
  • Eddy58Eddy58 Membre
    23:35 modifié #10
    dans 1186406421:

    Euh, peut-être il faut que je précise que la suppression se fait dans une énumération qui se fait tous les 10 secondes (NSTimer) ?

    Avec un NSEnumerator ? Il n'est pas conseillé de modifier une structure énumérée, il vaut mieux passer par une boucle for...next classique.
  • schlumschlum Membre
    23:35 modifié #11
    dans 1186406421:

    Euh, peut-être il faut que je précise que la suppression se fait dans une énumération qui se fait tous les 10 secondes (NSTimer) ?


    Comment ça ? Tu maà®trises ta mémoire avec un NSTimer ?? J'ai pas trop compris, mais vu comme ça ça ne me paraà®t pas très sérieux  ??? :P
  • TchouboudouTchouboudou Membre
    23:35 modifié #12
    En fait, c'était un test que j'avais fait, et que j'avais continuer. Bon, je vais reprendre depuis le début.

    J'ai un tableau. Ce tableau contient un dictionnaire qui lui-même contient une chaà®ne et une date.
    Toutes les 10 secondes, une fonction est appelé pour savoir si la date du dictionnaire (il peut y avoir plusieurs dictionnaire, mais là , c'est pour l'exemple :) ) correspond à  la date de maintenant (jour/mois/année et heure/minutes).
    Si elle est la même, j'éxécute une fonction, qui ouvre une fenêtre et qui supprime l'objet du tableau.

    Malheuresement, il y a toujours un blocage lorsque je supprime l'objet.

    Voici le code de la fonction appelé toutes les 10 secondes :

    - (void)searchNotes:(NSTimer *)aTimer<br />{<br />	NSEnumerator *e = [notes objectEnumerator];<br />	id tmp;<br />	<br />	while (tmp = [e nextObject])<br />	{<br />		NSCalendarDate *date = [tmp objectForKey:@&quot;Date&quot;];<br />		<br />		if ([[NSCalendarDate calendarDate] dayOfMonth] == [date dayOfMonth]<br />			&amp;&amp; [[NSCalendarDate calendarDate] monthOfYear] == [date monthOfYear]<br />			&amp;&amp; [[NSCalendarDate calendarDate] yearOfCommonEra] == [date yearOfCommonEra]<br />			&amp;&amp; [[NSCalendarDate calendarDate] hourOfDay] == [date hourOfDay]<br />			&amp;&amp; [[NSCalendarDate calendarDate] minuteOfHour] == [date minuteOfHour])<br />		{<br />			[self createStickyWithString:tmp];<br />		}<br />	}<br />	<br />	if ([notes count] == 0)<br />	{<br />		[timer invalidate];<br />		[timer release];<br />		flagTimer = NO;<br />	}<br />}
    


    Et le code createStickyWithString :

    - (void)createStickyWithString:(NSDictionary *)dictionary<br />{<br />	StickiesController *newSticky = [[StickiesController alloc] initWithString:[dictionary objectForKey:@&quot;String&quot;]];<br />	[newSticky showWindow:self];<br />	<br />	[notesShowed addObject:newSticky];<br />&nbsp; &nbsp; &nbsp; &nbsp; [notes removeObject:dictionary];<br />}
    


    Voili, voilou...
  • schlumschlum Membre
    23:35 modifié #13
    Regarde ce qu'a dit Eddy58 ci-dessus...

    Il est bien précisé dans la doc de la méthode "objectEnumerator" :

    When this method is used with mutable subclasses of NSArray, your code shouldn't modify the array during enumeration.
  • TchouboudouTchouboudou Membre
    août 2007 modifié #14
    ça commence à  m'énerve cette histoire ^^ .

    Dans la fonction appelé toutes les 10 secondes, j'ai mis un tableau temporaire. Au lieu de supprimer l'objet, je le met dans le tableau. Puis, après la boucle, je supprime les objets avec [notes removeObjectsInArray:array];

    Malheuresement, toujours le même problème.

    EDIT : Vous allez rigoler (ou pas), mais le problème venait absolument pas du tableau, mais du timer auquel je faisait un release alors qu'il n'avait pas été retenu :D

    En tout cas, merci beaucoup tout le monde !
Connectez-vous ou Inscrivez-vous pour répondre.