Приостановка NSTimer

У меня есть UIView с UITableView и UIImageView в нем. UITableView занимает верхнюю половину UIView. UIImageView занимает нижнюю половину UIView.

Я использую NSTimer для обновления изображения, отображаемого в UIImageView. Обычно каждые 3 секунды UIImageView загружает новый UIImage.

Проблема в том, что если я выберу строку из UITableView, NSTimer продолжит работу. Как я могу остановить NSTimer на didSelectRowFromIndexPath, а затем запустить его снова, когда представление вернется на экран?

-(void)viewDidLoad {
NSThread* timerThread = [[NSThread alloc] initWithTarget:self selector:@selector(startTimerThread) object:nil]; //Create a new thread
    [timerThread start]; //start the thread

} // end viewDidLoad

//
-(void) startTimerThread {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
    [[NSTimer scheduledTimerWithTimeInterval: 3.0
                                      target: self
                                    selector: @selector(loadNextPhoto)
                                    userInfo: nil
                                     repeats: YES] retain];

    [runLoop run];
    [pool release];
}

person Chris    schedule 02.05.2011    source источник
comment
Несколько хороших ответов ... спасибо.   -  person Chris    schedule 04.05.2011


Ответы (4)


Сохраните ссылку на созданный вами таймер, чтобы вы могли остановить его при необходимости. В следующий раз, когда он вам понадобится, вы можете просто создать новый таймер. Похоже, что лучше всего это сделать в viewDidAppear: и viewWillDisappear :. Я не уверен, почему вы запускаете таймер в новом потоке. У вас могут быть веские причины для этого, но мне никогда не приходилось этого делать.

//This code assumes you have created a retained property for loadNextPhotoTimer

    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        [self startTimer];
    }

    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        [self stopTimer];
    }

    - (void)startTimer {
        NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:3.0] interval:3.0 target:self selector:@selector(loadNextPhoto) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        self.loadNextPhotoTimer = timer;
        [timer release];
    }

    - (void)stopTimer {
        [self.loadNextPhotoTimer invalidate];
        self.loadNextPhotoTimer = nil;
    }
person jaminguy    schedule 02.05.2011
comment
это решение не работает для меня ... Мой таймер создан с помощью scheduleTimerWithTimeInterval: target: selector: userInfo: Repeats: ... должен ли я явно указывать цикл выполнения, в который нужно добавить таймер? - person Mohit Athwani; 31.05.2014
comment
Хорошо, я изменил свою реализацию startTimer, чтобы она была такой же, как указано выше, и она работает .... - person Mohit Athwani; 31.05.2014

Вы можете использовать метод invalidate NSTimer, чтобы уничтожить таймер.

Затем вам придется воссоздать его, как вы это делали в методе startTimerThread, когда вы вернетесь в представление.

person Macmade    schedule 02.05.2011

Чтобы получить доступ к потоку извне метода startTimerThread, вы должны добавить свойство в свой класс. Я бы предложил свойство над ivar, потому что вы можете автоматически синтезировать атомарные аксессоры. То, что вы делаете с таймером, зависит от того, хотите ли вы его приостановить или остановить.

Остановка таймера означает, что в следующий раз, когда вы запустите его, он запустится с оставшимися полными 3 секундами. Это означает, что если таймер сработает через 1 секунду, когда вы его остановите, ему все равно потребуется 3 секунды, чтобы сработать после того, как вы снова запустите его. Однако остановиться очень просто. stopTimerThread будет определяться следующим образом:

- (void)stopTimerThread {
    NSTimer *theTimer = self.timer;
    [theTimer invalidate];
    self.timer = nil;
}

Поскольку цикл выполнения в другом вашем потоке теперь не имеет источников, он автоматически завершится, и поток завершится, поэтому вы можете использовать startTimerThread, когда захотите запустить его снова.

Приостановка таймера означает, что если он сработает через 1 секунду, когда вы поставите его на паузу, он сработает через 1 секунду после перезапуска. Для этого вам также понадобится свойство, содержащее время, оставшееся до срабатывания таймера, которое будет установлено в stopTimerThread и использовано в startTimerThread. Реализация stopTimerThread выглядит следующим образом:

- (void)stopTimerThread {
    NSTimer *theTimer = self.timer;
    NSDate *fireDate = [theTimer fireDate];
    [theTimer invalidate];
    self.timerTimeRemaining = - [fireDate timeIntervalSinceNow];
    self.timer = nil;
}

Обратите внимание, что оставшееся время установлено как отрицательное значение временного интервала, поскольку дата возгорания будет раньше. Вам также придется изменить startTimerThread, чтобы учесть оставшееся время при настройке таймера.

- (void)startTimerThread {
    // set up autorelease pool, get run loop
    NSTimeInterval timeLeft = self.timerTimeRemaining;
    if(timeLeft <= 0.0) timeLeft = 3.0;
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:timeLeft];
    NSTimer *theTimer = [[NSTimer alloc] initWithFireDate:fireDate interval:3.0 target:self selector:@selector(loadNextPhoto) userInfo:nil repeats:YES];
    [runLoop addTimer:theTimer forMode:NSDefaultRunLoopMode];
    self.timer = theTimer;
    [theTimer release];
    [runLoop run];
    // clean up
}
person ughoavgfhw    schedule 02.05.2011

Создайте флаг (BOOL) для управления обновлением изображения.

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

-(void)ImageUpdater:(NSTimer *)theTimer
{
  if(image_updates_enabled)
  {
     // Code to update image
  }
}

Поскольку вы запускаете метод только каждые три секунды, нет ничего страшного в том, чтобы просто запустить таймер.

Еще вы можете настроить таймер так, чтобы он не повторялся. После этого решение о повторном включении таймера может быть принято где-нибудь в другом месте вашего кода, а не автоматически. Вы даже можете сделать это в функции обратного вызова и по-прежнему использовать флаг image_updates_enabled, если хотите.

person martin's    schedule 03.05.2011