NSTimer прерывается при нажатии кнопок во второй раз при загрузке представления

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

Первая загрузка игрового вида в жизненном цикле приложения работает отлично: никаких подтормаживаний при нажатии на кнопку и обновлении данных ядра. Но когда я отодвигаю тот же вид игры в жизненном цикле приложения, нажатия кнопок делают индикатор выполнения прерывистым и безответственным.

Разве NSTimer не аннулируется должным образом в цикле выполнения? Должен ли я вместо этого использовать CADisplayLink, хотя мое представление не использует много ресурсов?

Заранее спасибо.

Вот мой код:

Объявление таймера в файле .h:

@property (weak, nonatomic) NSTimer *updatetimer;

Создание таймера в viewDidLoad:

self.updatetimer = [NSTimer timerWithTimeInterval:counterStep target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.updatetimer forMode:NSRunLoopCommonModes];

функция updateProgress:

  - (void)updateProgress
    {
        //compute current time
        currentTime = currentTime - counterStep;

        //set timer label to int value of current time
        self.timerLabel.text = [[NSString alloc] initWithFormat:@"%d",[[NSNumber numberWithDouble:currentTime] intValue]];

        //update progress bar accordingly
        [self.progressbar setProgress: currentTime / totalTime animated:YES];

        if(currentTime <= 0) 
        {   
            //call the method that invalidates the timer + pushes to the next view
            [self overallTimeEnd];
        }
    }

Недействительность таймера:

[self.updatetimer invalidate];
self.updatetimer = nil;

person pepollet    schedule 10.07.2014    source источник
comment
Где вы отключаете таймер? Надеюсь, не dealloc. Вы подтвердили, что попали в эту очередь?   -  person Rob    schedule 10.07.2014
comment
Таймер становится недействительным в функции, вызываемой селектором таймера, когда оставшееся время меньше 0. Я не использую Dealloc на таймере. И да, инвалидация правильно вызывается каждый раз перед выходом из представления.   -  person pepollet    schedule 10.07.2014
comment
лучшая практика в программировании игр заключается в том, что вы используете один CADisplayLink в своем приложении в одном основном объекте... и оттуда вы вызываете функции в своих представлениях, если это необходимо (например, каждые 10 кадров или по прошествии определенного времени)   -  person Bastian    schedule 10.07.2014
comment
Я прочитал этот ответ в других темах и готов применить это решение, но я не могу понять, почему оно работает гладко при первой загрузке представления, но не в другие разы.   -  person pepollet    schedule 10.07.2014


Ответы (2)


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

Но давайте предположим, что проблема действительно в том, что updateProgress не вызывается с желаемой частотой. Если это так, то, вероятно, что-то, что вы используете в этом основном потоке, не позволяет таймеру работать с желаемой частотой. Трудно сказать, не видя, что делает updateProgress, не говоря уже о том, что еще может быть запущено в основном потоке. Видео WWDC 2012 Создание параллельных пользовательских интерфейсов на iOS показывает, как использовать инструменты чтобы найти то, что может негативно повлиять на параллельный UX.

Наконец, неясно, что лежит в основе процесса, о котором updateProgress информирует нас, но если вы можете перейти к подходу, управляемому событиями (например, при сетевом подключении, обновить пользовательский интерфейс, когда вызывается didReceiveData, а не использовать таймер). Иногда вам приходится использовать таймеры, но если вы можете их избежать, вы можете повысить эффективность приложения.

person Rob    schedule 10.07.2014
comment
спасибо за ссылку на видео, позже посмотрю. Что касается содержимого функции updateProgress, я добавил ее в свой вопрос. - person pepollet; 10.07.2014
comment
@pepollet Там нет ничего экстравагантного, так что вряд ли это проблема. У вас должно быть что-то еще, занимающее основной поток. Надеюсь, инструменты помогут вам определить проблему. (К вашему сведению, хотя я согласен с тем, что если вы делаете анимацию вручную, отображаемая ссылка имеет больше смысла, я не вижу здесь ничего, что можно было бы улучшить с помощью отображаемой ссылки по сравнению с таймером. Не помешает попробовать, но я удивлюсь, если это решит проблему.) - person Rob; 10.07.2014

Итак, наконец-то нашел причину, из-за которой мой таймер не освобождался в течение жизненного цикла приложения: я не использовал этапы раскрутки в своей раскадровке для возврата между представлениями, а стандартные переходы push. Никогда такими раньше не пользовался и не знал о них... Спасибо всем за помощь.

person pepollet    schedule 10.07.2014