Crash lors de l'utilsation de NSTimer

chbrossochbrosso Membre
juillet 2007 modifié dans API AppKit #1
Bonjour à  tous,

Programmeur C++, je me mets à  Cocoa avec une application qui incrémente un compteur toutes les secondes. J'ai donc fait mon nib, avec le textfield et le controlleur qui va bien, et j'ai rajouté un NSTimer dans le contrôleur:
<br />@interface UpController : NSObject<br />{<br />&nbsp; &nbsp; IBOutlet Upper *up;<br />&nbsp; &nbsp; IBOutlet NSTextField *valueField;<br /><br />&nbsp; &nbsp; NSTimer* timer;<br />}<br />- (IBAction)up:(id)sender;<br />- (void)awakeFromNib;<br />- (void) dealloc ;<br />@end<br />


Dans l'implémentation, j'initialise mon timer avec la méthode d'incrémentation de mon contrôleur, et je l'invalide à  la désallocation:
@implementation UpController<br /><br />- (IBAction)up:(id)sender<br />{<br />&nbsp; [valueField setIntValue:[up upIt]];<br />}<br /><br />- (void)awakeFromNib<br />{<br />&nbsp; [valueField setIntValue:0];<br />&nbsp; timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(up:) userInfo:nil repeats:TRUE];<br />}<br /><br />- (void) dealloc <br />{<br />&nbsp; [timer invalidate];<br />&nbsp; [super dealloc];<br />}<br />


Tout se passe bien, le comportement est celui que j'attends. Sauf que quand je ferme la fenêtre, j'ai un crash dans le NSRunLoop:
<br />#0	0x90a594d1 in objc_msgSend<br />#1	0x00337d60 in ??<br />#2	0x9283b2de in __NSFireTimer<br />#3	0x9082d7e2 in CFRunLoopRunSpecific<br />#4	0x9082cace in CFRunLoopRunInMode


J'ai l'impression que le timer est déclenché à  un moment où la cible (mon contrôleur) n'existe plus, mais je ne comprends pas... Qu'est-ce qui ne va pas?

Merci pour votre aide,

Charles

Réponses

  • BruBru Membre
    juillet 2007 modifié #2
    Quand tu fermes ta fenêtre, tu désalloues tous les objets qu'elle contient (notamment le textField).
    Ton contrôleur, lui, n'est pas désalloué, donc le timer continue à  fonctionner (car il n'appartient pas à  la fenêtre).
    Or, la méthode du timer va tenter de modifier la valeur du textField détruit...

    Résultat ? Crash !

    .
  • chbrossochbrosso Membre
    23:14 modifié #3
    OK, donc il faut que mon contrôleur soit désalloué quand la fenêtre se ferme... Comment faire? :why?:
  • BruBru Membre
    23:14 modifié #4
    Implante le delegate windowWillClose: dans ton contrôleur (et relie celui-ci à  ta fenêtre).
    Ce delegate sera appelé à  la fermeture de la fenêtre : c'est donc dans cette méthode que tu dois invalider le timer.

    Le contrôleur n'a pas besoin d'être désalloué.

    .
  • schlumschlum Membre
    23:14 modifié #5
    Autre solution : directement dans la méthode "close" de la fenêtre si celle-ci est une sous-classe perso.
  • chbrossochbrosso Membre
    23:14 modifié #6
    dans 1183496707:

    Implante le delegate windowWillClose: dans ton contrôleur (et relie celui-ci à  ta fenêtre).
    Ce delegate sera appelé à  la fermeture de la fenêtre : c'est donc dans cette méthode que tu dois invalider le timer.

    Le contrôleur n'a pas besoin d'être désalloué.

    .

    Merci beaucoup, maintenant ça marche!
Connectez-vous ou Inscrivez-vous pour répondre.