2010-06-09 5 views
5

Sono in esecuzione di un ciclo principale a Cocoa utilizzando un NSTimer impostato in questo modo:intervallo di sostituzione NSTimer per la ripetizione del timer

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

all'avvio del programma ho impostato il TimeInterval a 0.0 in modo che il ciclo principale viene eseguito il più velocemente possibile. Ad ogni modo, vorrei fornire una funzione per impostare il framerate (e quindi l'intervallo di tempo del timer) su un valore specifico in fase di esecuzione. Purtroppo per quanto ne so che significa che ho per reinizializzare il timer dal cacao non fornisce una funzione come "setTimerInterval" Questo è quello che ho provato:

- (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]; 
} 

ma questo getta il seguente errore e interrompe il ciclo principale :

2010-06-09 11: 14: 15,868 MyTarget [7313: a0f] setFrameRate 2010-06-09 11: 14: 15,868 MyTarget [7313: a0f] * __NSAutoreleaseNoPool(): Object 0x40cd80 di class __NSCFDate autoreleased senza pool sul posto - solo perdite 2010-06-09 11: 14: 15.869 myTarget [7313: a0f] * __NSAutoreleaseNoPool(): Object 0x40e700 di classe NSCFTimer autoreleased senza piscina in posto - solo che perde 0,614628

Ho anche cercato di ricreare il timer utilizzando la parola chiave "mantenere", ma che non ha cambiato nulla. Qualche idea su come modificare dinamicamente l'intervallo di un NSTimer in fase di runtime?

Grazie!

risposta

0

Non si dovrebbe rilasciare mainLoopTimer.
Quando lo hai creato, hai ricevuto un'istanza autorizzata e il runloop mantiene il riferimento a tale istanza.
Sarà rilasciato quando lo rimuovi dal ciclo: se lo rilasci manualmente, viene eliminato e il runloop tenta di accedere a un oggetto non valido.
Ecco perché si blocca.

EDIT: Ho completamente letto male e ho pensato di aver visto il rilascio quando era un invalido, mi dispiace. Il problema sembra essere che non ci sia AutoreleasePool in posizione. Questo è solitamente fatto in main(): creare il pool autorelease come la prima cosa

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

e rilasciarlo appena prima di uscire dalla principale.

Dai uno sguardo allo here per la documentazione dei pool Autorelease.

+0

cosa devo fare invece di cambiare l'intervallo? – moka

+0

Chiedo scusa. Ho letto male [versione mainLoopTimer]. Si sta agendo correttamente con il timer, ma sembra non esserci AutoReleasePool in posizione. dare un'occhiata qui: http://developer.apple.com/mac/library/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html – garph0

+0

hmm Ho già provato a mettere un autoreleasepool sul posto, ma non ha funzionato , ma ci riproverò! – moka

-2

È possibile provare a annullare la registrazione del timer precedente e avviarne uno nuovo con frequenza diversa. è possibile annullare la registrazione da

[yourOldTimer invalidate]; 
yourOldTimer = nil; 

Questo potrebbe risolvere lo scopo.

+0

come puoi vedere, questo è quello che ho già fatto e non funziona. – moka

3

Lo so, questo thread è fantastico vecchio! Ma ero alla ricerca anche della funzionalità!

Come si è scoperto, che il NSTimes non fornisce questa funzionalità, ho deciso di costruirne uno proprio. Non è la soluzione migliore, ma nel mio caso era l'unica possibile.

Ho definito la variabile "BOOL keepOn;" nel mio colpo di testa.

-(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]; 
    } 
} 

Il (molto) bis problema è, che il "timer" è in attesa tutto il ritardo, prima di poter ottenere un nuovo valore. Vedete, non risponde velocemente :)) E non potete fermarlo immediatamente (dovete aspettare che il ritardo finisca).

E se lo interrompi, sta lanciando un'altra azione come supposto.

In realtà funziona per il mio ed è ok per piccole app e strumenti.