Размещение NSTimer в отдельном потоке - PullRequest
8 голосов
/ 26 апреля 2010

Примечание: Вероятно, стоит прокрутить вниз, чтобы прочитать мои правки.

Я пытаюсь настроить NSTimer в отдельном потоке, чтобы он продолжал срабатывать, когда пользователи взаимодействуют с пользовательским интерфейсом моего приложения. Кажется, это работает, но Leaks сообщает о ряде проблем - и я считаю, что я сузил его до своего кода таймера.

В настоящее время происходит то, что updateTimer пытается получить доступ к NSArrayController (timersController), который связан с NSTableView в интерфейсе моих приложений. Оттуда я беру первую выбранную строку и изменяю ее столбец timeSpent. Примечание. Содержимое timersController представляет собой набор управляемых объектов, созданных с помощью Core Data.

Из прочтения я считаю, что я должен попытаться выполнить функцию updateTimer в главном потоке, а не во втором потоке таймеров.

Я пишу здесь в надежде, что кто-то с большим опытом может сказать мне, если это единственное, что я делаю неправильно. Прочитав документацию Apple по Threading, я обнаружил, что это чрезвычайно обширная тематическая область.

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

Я все еще совершенно потерян в отношении этой утечки. Я знаю, что, очевидно, что-то делаю не так, но я разобрал свое приложение до гола и до сих пор не могу его найти. Для простоты я загрузил код контроллера своего приложения в: небольшую вставку . Обратите внимание, что теперь я удалил код потока таймера и вместо этого решил запустить таймер в отдельном цикле выполнения (как предлагается здесь).

Если я настрою дерево вызовов утечек, чтобы скрыть как отсутствующие символы, так и системные библиотеки, мне будет показан следующий вывод:

РЕДАКТИРОВАТЬ: Ссылки на скриншоты повреждены и поэтому удалены.

1 Ответ

51 голосов
/ 27 апреля 2010

Если единственной причиной, по которой вы создаете новый поток, является то, что ваш таймер работает, когда пользователь взаимодействует с пользовательским интерфейсом, вы можете просто добавить его в различных режимах запуска:

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

В качестве дополнения к этому ответу теперь можно планировать таймеры с помощью Grand Central Dispatch и блоков:

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

Позже, когда таймер больше не нужен:

dispatch_source_cancel(_timer);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...