2010-06-09 2 views
5

Je dirigeais une MainLoop à Cocoa en utilisant un NSTimer mis en place comme ceci:Intervalle de changement NSTimer pour répéter la minuterie

 mainLoopTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/fps target:self selector:@selector(mainloop) userInfo:nil repeats:YES]; 
    [[NSRunLoop currentRunLoop] addTimer:mainLoopTimer forMode:NSEventTrackingRunLoopMode]; 

Au démarrage du programme, je mis la timeInterval à 0.0 afin que le mainloop court aussi vite que possible. Quoi qu'il en soit, je voudrais fournir une fonction pour régler le framerate (et donc l'intervalle de temps de la minuterie) à une valeur spécifique à l'exécution. Malheureusement, pour autant que je sache, cela signifie que je dois réinitialiser la minuterie puisque Cocoa ne fournit pas une fonction comme « setTimerInterval » Voilà ce que j'ai essayé:

- (void)setFrameRate:(float)aFps 
{ 
    NSLog(@"setFrameRate"); 
    [mainLoopTimer invalidate]; 
    mainLoopTimer = nil; 

    mainLoopTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/aFps target:self selector:@selector(mainloop) userInfo:nil repeats:YES]; 
    [[NSRunLoop currentRunLoop] addTimer:mainLoopTimer forMode:NSEventTrackingRunLoopMode]; 
} 

mais cela jette l'erreur suivante et arrête le mainloop :

2010-06-09 11: 14: 15,868 MyTarget [7313: a0f] setFrameRate 09/06/2010 11: 14: 15,868 MyTarget [7313: a0f] * __NSAutoreleaseNoPool(): Object 0x40cd80 de class __NSCFDate libéré sans pool en place - juste fuite 2010-06-09 11: 14: 15.869 myTarget [7313: a0f] * __NSAutoreleaseNoPool(): Object 0x40e700 de classe NSCFTimer autoreleased sans piscine en place - juste une fuite 0,614628

J'ai aussi essayé de recréer la minuterie en utilisant le mot-clé « conserver », mais cela ne change rien. Des idées sur la façon de modifier dynamiquement l'intervalle d'un NSTimer à l'exécution?

Merci!

Répondre

0

Vous ne devez pas libérer mainLoopTimer.
Lorsque vous l'avez créé, vous avez reçu une instance de mise à jour automatique et la boucle de lancement conserve la référence à cette instance.
Il sera libéré lorsque vous le retirerez de la boucle: si vous le relâchez manuellement, il sera supprimé et la boucle de démarrage tentera d'accéder à un objet non valide.
C'est pourquoi il se bloque.

EDIT: J'ai totalement mal lu et j'ai pensé que j'ai vu la libération quand il était invalide, désolé. Le problème semble être qu'il n'y a pas de AutoreleasePool en place. Cela se fait habituellement en main(): créer le pool autorelease comme la première chose

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

et relâchez juste avant la sortie de la principale.

Jetez un coup d'œil here pour la documentation des pools Autorelease.

+0

Que devrais-je faire au lieu de changer l'intervalle? – moka

+0

Je vous demande pardon. J'ai mal lu [mainLoopTimer version]. Vous agissez correctement avec le minuteur, mais il semble qu'il n'y ait pas de AutoReleasePool en place. jetez un oeil ici: http://developer.apple.com/mac/library/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html – garph0

+0

hmm J'ai déjà essayé de mettre en place un autoreleasepool en place, mais cela n'a pas fonctionné , mais je vais essayer à nouveau! – moka

-2

Vous pouvez essayer de dés-enregistrer la minuterie précédente et en démarrer une nouvelle avec une fréquence différente. vous pouvez désenregistrer par

[yourOldTimer invalidate]; 
yourOldTimer = nil; 

Cela pourrait résoudre le but.

+0

comme vous pouvez le voir, c'est ce que j'ai déjà fait, et ça ne marche pas. – moka

3

Je sais, ce fil est incroyable vieux! Mais j'étais à la recherche de la fonctionnalité aussi!

Comme il s'est avéré, que le NSTimes ne fournit pas cette fonctionnalité, j'ai décidé d'en créer un. Ce n'est pas la meilleure solution, mais dans mon cas c'était le seul possible.J'ai défini la variable "BOOL keepOn;" dans mon en-tête.

-(IBAction)doSomething:(id)sender 
{ 
    // Any action to throw every interval. 
} 

-(IBAction)switchAutoLoad:(id)sender 
{ 
    if([autoLoad state] == NSOffState) 
    { 
     NSLog(@"auto-reload on!"); 

     self performSelector:@selector(fireTimer) withObject:nil afterDelay:0]; 
     keepOn = YES; 
     [autoLoad setState:NSOnState]; 
    } 
    else 
    { 
     NSLog(@"auto-reload off!"); 
     keepOn = NO; 
     [autoLoad setState:NSOffState]; 
    } 
} 

-(void)fireTimer 
{ 
    [self doSomething:nil]; 

    float theTime = 20; // This is the time interval. 

    if(keepOn) 
    { 
     [self performSelector:@selector(fireTimer) withObject:nil afterDelay:theTime]; 
    } 
} 

Le (très) bis est question, que le « timer » attend le retard tout, avant de pouvoir obtenir une nouvelle valeur. Vous voyez, il ne répond pas rapidement :)) Et vous ne pouvez pas l'arrêter immédiatement (il faut attendre que le délai se termine).

Et si vous l'arrêtez, il lance une autre action comme supposé.

En fait cela fonctionne pour mon et est ok pour les petites applications et les outils.