2013-05-15 2 views
9

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

pingTimer = [[NSTimer alloc] initWithFireDate:pingAtDate 
            interval:0 
             target:self 
            selector:@selector(ping:) 
            userInfo:nil 
             repeats:NO]; 

[[NSRunLoop currentRunLoop] addTimer:pingTimer forMode:NSDefaultRunLoopMode]; 

дата приблизительно 1 неделя в будущем, поэтому для тестирования цели I (и другие) устанавливают системные часы вперед 8 дней, чтобы гарантировать, что указанное событие произойдет. Проблема в том, что этого не происходит.

При планировании в течение нескольких минут в будущем я заметил, что таймер по-прежнему отключается, но, похоже, он отключается через определенное количество минут. Скажем, я планирую таймер на дату 5 минут в будущем, затем я устанавливаю часы вперед 1 час, таймер действительно срабатывает через 5 минут, но поскольку я устанавливаю часы вперед на 1 час, время, когда оно срабатывает, больше не выравнивается со временем, когда он должен был стрелять.

Это не то, что я ожидал бы, поскольку я называю «initWithFireDate».

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

+3

«NSTimer» не является механизмом настенных часов; вы не должны ожидать, что он будет надежным через неделю. См. [Расписание нескольких ежедневных событий с помощью NSTimer] (http: // stackoverflow.com/q/2632996) и [Есть ли определенный способ иметь долгосрочный NSTimer fire?] (http://stackoverflow.com/q/8449351) –

+0

Является ли ваш цикл запуска фактически обработкой событий за время до таймера пожары? Я мог представить себе, что если таймер является единственным источником в цикле выполнения (или, по крайней мере, единственным источником, который когда-либо имел событие), тогда цикл цикла не будет замечать, что настенные часы изменились. Но это чистая спекуляция. –

+0

@JoshCaswell, что на самом деле не проблема, проблема в том, что если вы установите таймер на 1 минуту в будущем, тогда установите системные часы на 2 минуты в будущем, он все равно будет срабатывать в одну минуту. –

ответ

24

Были оставлены хорошие комментарии, но нет полных ответов. Здесь я собираюсь собрать все соответствующие детали.

NSTimer не является механизмом часов. Когда вы устанавливаете «FireDate», вы не можете быть уверены, что таймер будет срабатывать в этот день. Вы фактически говорите таймеру работать в течение определенного количества времени перед стрельбой. Этот промежуток времени - это разница между тем, когда вы добавляете таймер в цикл выполнения, и дату, когда вы планировали запуск таймера.

Если ваша система переходит в спящий режим (или приложение приостановлено), ваш таймер перестает мигать. Он возобновит тиканье, когда ваша система просыпается (или ваше приложение становится активным), но это означает, что ваш таймер теперь НЕ будет выполняться в оригинальной «FireDate». Скорее, он будет выполняться на «FireDate» + (время, в течение которого ваш компьютер спал).

Аналогично, если пользователь меняет системное время, это никак не влияет на таймер. Если таймер был запланирован на следующий день в 8 часов, он будет продолжать тикать до 8 часов, прежде чем он начнет гореть.

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

  1. из спящего режима
  2. Срочное изменение системы

При возникновении любого из этих событий вам необходимо будет аннулировать и настроить любые существующие таймеры.

/* If the clock time changed or we woke from sleep whe have to reset these long term timers */ 
- (void) resetTimers: (NSNotification*) notification 
{ 
    //Invalidate and Reset long term NSTimers 
} 

Вы можете наблюдать следующие уведомления, которые будут уведомлены о произошедших событиях.

[[NSNotificationCenter defaultCenter] addObserver:self       
             selector:@selector(resetTimers:)    
              name:NSSystemClockDidChangeNotification    
              object:nil]; 

[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self 
                 selector:@selector(resetTimers:)   
                  name:NSWorkspaceDidWakeNotification 
                 object:nil]; 
+1

Хорошее резюме! Вы также можете взглянуть на [Выполнить код в определенное время в соответствии с системными часами] (http://stackoverflow.com/q/11404348). Хотя он ориентирован на OS X, вы можете найти его полезным. –

+0

@JoshCaswell - Это отличный и очень уместный пост. Мне жаль, что я не нашел его, когда впервые столкнулся с этой проблемой. –

Смежные вопросы