Colocando um NSTimer em um encadeamento separado

Nota: provavelmente vale a pena rolar para baixo para ler minha edição.

Eu estou tentando configurar um NSTimer em um segmento separado para que ele continue a triggersr quando os usuários interagem com a interface do usuário do meu aplicativo. Isso parece funcionar, mas Leaks relata vários problemas – e acredito que reduzi o código do timer.

Atualmente o que está acontecendo é que o updateTimer tenta acessar um NSArrayController (timersController) que é ligado a um NSTableView na interface de meus aplicativos. De lá, eu pego a primeira linha selecionada e altero sua coluna timeSpent. Nota: o conteúdo do timersController é uma coleção de objects gerenciados gerados via Core Data.

Da leitura ao redor, acredito que o que eu deveria estar tentando fazer é executar a function updateTimer no thread principal, em vez de no meu thread secundário timeres.

Estou postando aqui na esperança de que alguém com mais experiência possa me dizer se essa é a única coisa que estou fazendo de errado. Depois de ler a documentação da Apple sobre Threading, descobri que é uma área de assunto extremamente grande.

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

ATUALIZAR

Eu ainda estou totalmente perdida com relação a esse vazamento. Eu sei que, obviamente, estou fazendo algo errado, mas desnudei meu aplicativo até seu esqueleto e ainda não consigo encontrá-lo. Para simplificar, enviei o código do controlador de aplicativos para: um pequeno pastebin . Observe que agora removi o código de segmento do timer e optei por executar o timer em um runloop separado (como sugerido aqui).

Se eu definir a Árvore de Chamada Vazada para ocultar os Símbolos Ausentes e as Bibliotecas do Sistema, mostrarei a seguinte saída:

EDIT: Links para screenshots quebrados e, portanto, removidos.

Se a única razão pela qual você está gerando um novo thread é permitir que seu timer seja executado enquanto o usuário está interagindo com a UI, você pode simplesmente adicioná-lo em diferentes modos runloop:

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

Como um adendo a esta resposta, agora é possível programar timeres usando o Grand Central Dispatch e bloqueia:

 // 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); 

Mais tarde, quando o timer não for mais necessário:

 dispatch_source_cancel(_timer);