2010-04-26 13 views
8

Nota: Probabilmente vale la pena scorrere verso il basso per leggere la mia modifica.Inserimento di un NSTimer in una filettatura separata

Sto provando a configurare un NSTimer in un thread separato in modo che continui a sparare quando gli utenti interagiscono con l'interfaccia utente della mia applicazione. Questo sembra funzionare, ma Leaks riporta una serie di problemi - e credo di averlo ridotto al mio codice timer.

Attualmente ciò che accade è che updateTimer tenta di accedere a un NSArrayController (timersController) che è associato a un NSTableView nell'interfaccia delle mie applicazioni. Da lì, afferro la prima riga selezionata e modifica la sua colonna timeSpent. Nota: il contenuto di timersController è una raccolta di oggetti gestiti generati tramite Core Data.

Dalla lettura in giro, credo che ciò che dovrei provare a fare è eseguire la funzione updateTimer sul thread principale, piuttosto che sul thread secondario dei timer.

Sto postando qui nella speranza che qualcuno con più esperienza possa dirmi se è l'unica cosa che sto sbagliando. Dopo aver letto la documentazione di Apple su Threading, l'ho trovato un argomento molto vasto.

NSThread *timerThread = [[[NSThread alloc] initWithTarget:self selector:@selector(startTimerThread) object:nil] autorelease]; 
[timerThread start]; 

-(void)startTimerThread 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
    activeTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES] retain]; 

    [runLoop run]; 
    [pool release]; 
} 
-(void)updateTimer:(NSTimer *)timer 
{ 
    NSArray *selectedTimers = [timersController selectedObjects]; 
    id selectedTimer = [selectedTimers objectAtIndex:0]; 
    NSNumber *currentTimeSpent = [selectedTimer timeSpent]; 

    [selectedTimer setValue:[NSNumber numberWithInt:[currentTimeSpent intValue]+1] forKey:@"timeSpent"]; 
} 
-(void)stopTimer 
{ 
    [activeTimer invalidate]; 
    [activeTimer release]; 
} 

UPDATE

che sto ancora totalmente perso per quanto riguarda questa perdita. So che sto ovviamente facendo qualcosa di sbagliato, ma ho spogliato la mia applicazione fino alle sue ossa nude e ancora non riesco a trovarlo. Per motivi di semplicità, ho caricato il mio codice del controller delle applicazioni su: a small pastebin. Si noti che ora ho rimosso il codice del thread del timer e invece ho optato per eseguire il timer in un runloop separato (come suggerito qui).

Se ho impostato le perdite Chiamata albero per nascondere entrambi i simboli mancanti e librerie di sistema, che sto mostrato il seguente output:

EDIT: Collegamenti a immagini di rotto e Perciò rimosso.

+0

Perché si imposta un ciclo di esecuzione aggiuntivo? Il tuo timer può funzionare normalmente bene con il ciclo di esecuzione principale. – zneak

+0

Il collegamento pastebin è morto. –

risposta

51

Se l'unica ragione per cui si sta generando un nuovo thread è quello di consentire il timer per eseguire mentre l'utente interagisce con l'interfaccia utente si può semplicemente aggiungere che in diverse modalità runloop:

NSTimer *uiTimer = [NSTimer timerWithTimeInterval:(1.0/5.0) target:self selector:@selector(uiTimerFired:) userInfo:nil repeats:YES];  
[[NSRunLoop mainRunLoop] addTimer:uiTimer forMode:NSRunLoopCommonModes]; 

Come un addendum questa risposta è ora possibile programmare i timer che utilizzano Grand Central Dispatch e blocchi:

// Update the UI 5 times per second on the main queue 
// Keep a strong reference to _timer in ARC 
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); 
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, (1.0/5.0) * NSEC_PER_SEC, 0.25 * NSEC_PER_SEC); 

dispatch_source_set_event_handler(_timer, ^{ 
    // Perform a periodic action 
}); 

// Start the timer 
dispatch_resume(_timer); 

più tardi, quando il timer non è più necessaria:

dispatch_source_cancel(_timer); 
+0

Questa è una soluzione molto più maneggevole, grazie. Ho appena passato un po 'di tempo a leggere su runloop. Sfortunatamente, non sembra aiutare con la mia perdita. L'ho ristretto a (credo) un problema nella funzione updateTimer. Credo che abbia qualcosa a che fare con il modo in cui sto aggiornando la variabile timeSpent all'interno del mio NSArray di oggetti gestiti. – ndg

+0

Se il codice che hai postato sopra è la tua funzione updateTimer, mi sembra OK. Devi fare attenzione a non rilasciare un timer una volta che lo hai invalidato, però. – sbooth

+0

Questa è davvero la mia funzione updateTimer.Ho aggiornato l'OP per riassumere i problemi che sto vedendo (e per avere un aggiornamento sul codice usato). – ndg

Problemi correlati