[Cocoa]Problème d'évènements.

Askerat

Membre confirmé
14 Décembre 2008
20
0
Bonjour,

je suis nouveau sur le forum, je l'ai découvert en cherchant solution à mon sujet, pour me présenter rapidement, je suis en DUT informatique, et par avant j'ai pas mal pratiqué le Java/C++/php. J'ai commencé l'objective C que récemment, je commence à bien intégrer la logique du langage. Seulement je suis confronté à un comportement très étrange, j'espère qu'on saura me dire ce qui cloche.

Les fait :


Dans une même classe héritée de NSWindow j'ai trois messages :
-(void) keyDown:(NSEvent*)event {
[super event];
[self autreMessage:mad:"unString"];
}

-(void) autreMessage:(NSString*)str{
//Utilise le string envoyé.
NSLog(str); // s'affiche correctement dans tous les cas.
self->monString = [self->monString appendString:str]; //Et pourtant, ne s'ajoute pas si str vient de keyDown.
}

-(void) dernierMessage{
[self autreMessage:mad:"unString"];
}
Que keyDown soit appellé, ou que j'appelle moi-même dernierMessage, NSLog(str); dans autreMessage m'affiche bien unString dans les deux cas, sauf que si je l'envoie depuis dernierMessage, autreMessage se comporte correctement, et depuis keyDown non. En gros autreMessage fait un appendString sur une propriétée de classe. J'ai fait le test en statique dans les deux cas biensur, sans utiliser le retour de l'objet NSEvent de keyDown. J'ai tout tenté, des stringWithString: & co. Pas moyen d'ajouter le NSString str à mon autre NSString, si str provient de keyDown. Je me retrouve toujours avec une chaine qui vaut nil. D'ou celà peut-il venir ? J'ai tenté le code hors de mon projet avec une seule classe MyWindow qui reprend l'exemple.
 
myString is Mutable sure


Bloc de code:
- (void)appendString:([URL="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/c_ref/NSString"]NSString[/URL] *)aString

[self.myString appendString:[str retain]];
:rolleyes: " je commence à bien intégrer la logique du langage"
oui bof et puis la doc bof et le pointeur -> bof

"j'ai pas mal pratiqué le Java/C++/php"
c'est a dire au moins 5 ans sur des projets key?
 
Voici le message que j'utilise :

- (NSString *)stringByAppendingString:(NSString *)aString.

J'avais pas le source sous les yeux lorsque j'ai rédigé le message. Mais visiblement il se passe quelque chose de bizarre dans keyDown, puisque tout fonctionne bien si ma fonction est appellée ( de la meme maniere avec le meme parametre ) d'une autre fonction que keyDown.
 
J'ai tout de même du mal à comprendre de quelle manière le message keyDown peut altérer le comportement d'un message qu'il envoie. Car mon message, envoyé de la même manière, l'instruction est la même, je le répète, car c'est bien ce qui me gêne le plus dans l'histoire, ne fonctionne pas lorsque cet envoi est fait depuis keyDown. Dans tout autre contexte ça fonctionne.

J'ai par exemple essayé d'envoyer ce message via une action sur un bouton, et là ça marche. Surtout que dans tous les cas, ( keyDown, action bouton, ou statique ( appel dans init par exemple )) le message (autreMessage) m'affiche bien sur la sortie standart la bonne valeur de ma variable, puis lorsqu'il l'envoie à un autre message, je perds systématiquement la valeur, si la provenance du NSString vient de keyDown.
 
Bloc de code:
-(void) keyDown:(NSEvent*)event {
    [super event];
    [self autreMessage:@"unString"];
}

NSWindow n'a pas de méthode "event".


Bloc de code:
-(void) autreMessage:(NSString*)str
{
    //Utilise le string envoyé.
    NSLog(str); // s'affiche correctement dans tous les cas.
    self->monString = [self->monString appendString:str]; //Et pourtant, ne s'ajoute pas si str vient de keyDown.
}

self->monString: mais où es-tu aller chercher ça ?

Moi j'écrirais:
Bloc de code:
NSString* newString = [monString stringByAppendingString:str];
[monString release];
monString = [newString retain];

Comme le dit Tatouille (à sa façon…), il vaut mieux utiliser NSMutableString, dans ce cas là, c'est plus simple.


Franchement, ton code est du bricolage, il faut que tu apprennes les bases du langage ObjC, parce qu'il est clair que tu ne maîtrises pas ce que tu fais. Il ne faut pas que tu le prennes mal.

Inscris-toi ici.

Achète ce bouquin.
 
Ouais j'appelle bien keyDown, mais je vois pas où est le bricolage, puisque stringByAppendingString: retourne bien un nouveau NSString, je l'affecte donc naturellement. La méthode fonctionne très bien si l'appel n'est pas fait depuis keyDown, je le répète.
 
1) Supprime l'appel à
[super event];
et le message s'affichera certainement.

2) Après que la ligne
Bloc de code:
monString = [monString stringByAppendingString:str];
est executée
Que devient l'ancien objet pointé par monString ?
Jusqu'à quand l'objet monString va-t-il rester en mémoire ?
 
Bon j'ai déjà un peu tout tenté, j'ai ajouté un message pour voir justement jusqu'à quand existait ma chaine, ça nous donne donc :

-(void) keyDown: (NSEvent*)event {
//[super event];
[self autreMessage:mad:"unString"];
}

-(void) autreMessage: (NSString*)str{
//Utilise le string envoyé.
NSLog(str); // s'affiche correctement dans tous les cas.
[self encoreUnMessage:str];
NSLog(str); // S'affiche correctement dans tous les cas, donc str existe bien au sein de autreMessage, mais pas au sein de encoreUnMessage !

NSString *tmp = [self->monString stringByAppendingString:str];
[self->monString autorelease];
self->monString = [tmp retain];
}

-(void) encoreUnMessage:(NSString*) str{
NSLog(str); // Ne s'affiche pas lorsque l'origine de str est keyDown, s'affiche dans tous les autres cas.
}

-(void) dernierMessage{
[self autreMessage:mad:"unString"];
}



Si entre temps personne trouve solution au problème, je crée une petite archive qui souligne le problème au boulot, seulement j'ai que acces au protocole http, je pourrai donc répondre ici, mais je ne pourrai le mettre en ligne que vers 22h.

edit : Elle sera sous la forme d'un projet Xcode avec une simple classe fille de NSWindow qui aura un attribut et un bouton, afin de souligner différents appels du message qui nous cause tant de soucis.
 
J'ai repris ton code, j'ai juste modifié les méthodes de messages ainsi:

Bloc de code:
-(void) encoreUnMessage:(NSString*) str{
	NSLog(@"encoreUnMessage:%@", str);
}

et j'obtiens ça:

Bloc de code:
008-12-15 16:58:15.854 WindowResponder[1506:10b] autreMessage:unString
2008-12-15 16:58:15.863 WindowResponder[1506:10b] encoreUnMessage:unString
2008-12-15 16:58:15.867 WindowResponder[1506:10b] autreMessage:unString

Bref, ça marche.
 
Effectivement, j'ai reproduit la meme chose que toi, ça m'affiche la même chose, cependant, tente d'afficher sur la sortie standart le contenu de monString, tu verras qu'il ne s'affiche pas, car monString vaut toujours nil, hors, dans mon programme initial, lorsque la chaine vient d'une autre action, la concaténation se fait correctement.
 
Je pense avoir trouvé mon erreur. Juste une question, comment peut-on surcharger le constructeur de NSWindow ? Car visiblement init ne suffit pas. Et les initWithXXX meme en appellant [super initWithXXX] ne me rendent pas une fenetre complète.
 
Je l'ai pourtant bien surchargé ce constructeur, mais effectivement, au début ma classe Calculator n'héritait pas de NSWindow, et j'avais une instance contenue dans mon Controller, du coup, j'initialise mon Calculator et dans mon NSApplication et dans mon Controller, ce qui fait 2NSWindow pour une fenetre effective, le soucis vient sans doute de là, j'aurais du revoir plus en profondeur l'organisation de mes objets en voulant ajouter la gestion clavier.

Mais bon, je trouve un peu domage qu'on veuille éviter de faire faire de l'héritage aux utilisateurs sans proposer de solution convenable pour les évènements. J'ai beaucoup travaillé avec Swing, donc j'ai un peu vite tendance à spécialiser les classes disponibles. Là je suis entrain de reconstruire l'application.

Pour le livre, je l'ai commandé il y a deux jours sur amazon, il devrait arriver d'ici ce week end au plus tard à prioris.

Pour ce qui est des pointeurs, dis moi tatouille quel est le problème ? Je sors d'un an de dev en Java, et tous les exemples que je vois initialisent des objets avec des pointeurs. En java tout étant référence, le comportement doit être similaire, et il faut bien faire attention à ce que l'on met dans les méthodes copy ( clone en java ) de nos objets. A la différence pres que là on doit gérer la mémoire. Je pensais que le NSAutoreleasePool gérait ça, mais visiblement on doit le gérer de manière plus suivie que ce qu'il parait au premier abord, je vais donc regarder un peu plus par là dans les prochains temps.