Запуск и управление NSTimer в разных NSThread / NSRunLoop - PullRequest
2 голосов
/ 17 июня 2010

Я пишу приложение Какао с графическим интерфейсом, разработанным в Интерфейсном Разработчике.Мне нужно планировать фоновую активность (с регулярными интервалами), не блокируя пользовательский интерфейс, поэтому я запускаю ее в отдельном потоке, например:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    [self performSelectorInBackground:@selector(schedule) withObject:nil];
}

- (void) schedule {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];

    timer = [[NSTimer scheduledTimerWithTimeInterval:FEED_UPDATE_INTERVAL
                                                  target:activityObj
                                        selector:@selector(run:)
                                        userInfo:nil
                                         repeats:YES]
         retain];

    [runLoop run];
    [pool release];
}

Я сохраняю таймер, поэтому я могу легко аннулировать и перепланировать.

Проблема: я должен также запустить метод run: в ответ на события GUI, чтобы он был синхронным (т. Е. Кнопка «выполнить действие»).Вот так:

[timer fire];

Я мог бы сделать это и с помощью executeSelectorInBackground, и, конечно, он не блокирует пользовательский интерфейс.Но эта синхронная стрельба запускается в очередной прогон!Поэтому у меня нет гарантии, что они не будут пересекаться.Как я могу поставить в очередь все мои увольнения в одном и том же цикле выполнения?

Ответы [ 3 ]

0 голосов
/ 11 июля 2015

Вы можете использовать классическое решение для параллелизма: семафор. В вашем случае проще всего использовать директиву @synchronized. Окружите все тело (или, по крайней мере, чувствительную часть) метода run: с помощью @synchronized. Для объекта синхронизации я предлагаю вам использовать определенную ivar или статическую переменную вместо класса activityObj, чтобы избежать тупиков.

-(void)run:(id)param {
    // do thread-safe things here
    @synchronized(syncObj) {
        // put your critical section here
    }
    // do more thread-safe things here
}

Код в критическом разделе не будет перекрываться.

0 голосов
/ 27 февраля 2016

Вы должны запланировать NSTimer на mainThread (и запустить таймер для выполнения селектора --- селектор может выполняться в фоновом потоке, таким образом, не блокировать пользовательский интерфейс), а не планировать NSTimer в фоновом потоке через GCD, потому что NSTimer будет добавлен в NSRunLoop, и каждый NSRunLoop связан с NSTread. Поэтому при использовании GCD используйте dispatch_after вместо NSTimer, чтобы отложить события.

0 голосов
/ 18 июня 2010
[timer setFireDate:[NSDate distantPast]];

Я получил желаемый эффект, настроив дату следующего срабатывания как можно скорее, передав прошедшую дату в setFireDate.

...