2011-02-09 2 views
2

Я делаю приложение с таймером. Я подсчитываю минуты и секунды от заданного времени до 0. Когда это произойдет, я запускаю предупреждение.Thread and NSTimer

Моя структура такова:

метод Mainthread выделить новый поток и инициализировать его. Точка входа (метод) для потока имеет таймер, который вызывает метод вычисления оставшегося времени, а если время увеличивается, отображается предупреждение.

Однако, это правильно? Потому что теперь я обновляю GUI из другого потока, кроме основного ... и это плохо? И я также показываю alertview из этой темы.

Я думал о создании другого метода, который инкапсулирует всю логику для обновления и отображения предупреждения и в методе, который вызывает nstimer, использует performSelectorInMainThread, однако это правильно?

Спасибо за ваше время.

+0

как ваши часы идут? У меня есть аналогичная проблема, что мне нужно отслеживать URL каждые 2 секунды. Интересно, какое решение вы использовали. [email protected] – leo

ответ

4

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

- (void) initializeTimerWithEndTime: (NSDate *) endTime 
{ 
    // call this on the main thread & it'll automatically 
    // install the timer on the main runloop for you 
    self.countdownTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 
                  target: self 
                 selector: @selector(timerTick:) 
                 userInfo: endTime 
                  repeats: YES]; 
#if __TARGET_OS_IPHONE__ 
    // fire while tracking touches 
    [[NSRunLoop mainRunLoop] addTimer: self.countdownTimer 
           forMode: UITrackingRunLoopMode]; 
#else 
    // fire while tracking mouse events 
    [[NSRunLoop mainRunLoop] addTimer: self.countdownTimer 
           forMode: NSEventTrackingRunLoopMode]; 
    // fire while showing application-modal panels/alerts 
    [[NSRunLoop mainRunLoop] addTimer: self.countdownTimer 
           forMode: NSModalPanelRunLoopMode]; 
#endif 
} 

- (void) cancelCountdown 
{ 
    [self.countdownTimer invalidate]; 
    self.countdownTimer = nil; 
} 

- (void) timerTick: (NSTimer *) aTimer 
{ 
    NSDate * endDate = [timer userInfo]; 
    NSDate * now = [NSDate date]; 

    // have we passed the end date? 
    if ([endDate laterDate: now] == now) 
    { 
     // show alert 
     [self cancelCountdown]; 
     return; 
    } 

    // otherwise, compute units & show those 
    NSUInteger units = NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit; 

    NSDateComponents * comps = [[NSCalendar currentCalendar] components: units 
                   fromDate: [NSDate date] 
                   toDate: endDate 
                   options: 0]; 
    [self.clockView setHours: comps.hour 
        minutes: comps.minute 
        seconds: comps.second]; 
} 
+0

Но что происходит, когда пользователь держит, например. клетка? – LuckyLuke

+0

Также установите таймер на NSEventTrackingRunLoopMode или UIEventTrackingRunLoopMode, чтобы он все равно срабатывал при отслеживании событий ввода. –

+0

Я не нахожу такой постоянной. – LuckyLuke

1

Не нужно запускать таймер на вторичном потоке, просто создайте таймер на основном потоке. Вы не должны обновлять графический интерфейс из вторичного потока, да, вы могли бы использовать performSelectorInMainThread, но зачем беспокоиться? Просто поместите все это в основной поток, если ваш таймер не называется «слишком часто», производительность будет прекрасной.

+0

Если я поместил таймер в основной поток (обновляется каждую секунду, так как это часы), и пользователь блокирует runloop прикосновением, например, тогда часы останавливаются. – LuckyLuke