Остановить NSRunLoop по таймеру

Я сделал RunLoop с таймером, который обновляет метку, отображающую обратный отсчет. Мне нужно, чтобы RunLoop останавливался, когда обратный отсчет достигает нуля, для случая, когда таймер заканчивается нормально, я мог бы просто использовать runUntilDate, где дата является текущей датой + время обратного отсчета. Проблема заключается в том, что пользователь отменяет обратный отсчет с помощью кнопки до его завершения. Я не знаю, как сказать RunLoop остановить действие кнопки отмены. Вот код для RunLoop:

    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
                            [self methodSignatureForSelector:@selector(updateCountdownLabel:)]];
[invocation setTarget:self];
[invocation setSelector:@selector(updateCountdownLabel:)];
[[NSRunLoop mainRunLoop] addTimer:[NSTimer timerWithTimeInterval:1 invocation:invocation repeats:YES] forMode:NSRunLoopCommonModes];

Метод просто сообщает метке уменьшить на 1 в каждом цикле.

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

cancelPerformSelector:target:argument:

cancelPerformSelectorsWithTarget:

Это самые близкие, которые я нашел, но они, похоже, не работают внутри собственного селектора RunLoops, или, по крайней мере, я не пробовал их никоим образом.

В основном мне нужно, чтобы кнопка останавливала RunLoop или каким-то образом останавливала RunLoop из своего собственного селектора.

Спасибо.


person Elbimio    schedule 08.07.2011    source источник
comment
Селектор — это просто имя метода. Я исправил ваше употребление этого слова в моем редактировании.   -  person Peter Hosey    schedule 08.07.2011


Ответы (1)


Вы не создали цикл выполнения, вы запланировали запуск таймера в основном цикле выполнения.

Что вам нужно сделать, так это сохранить объект NSTimer, который вы создаете, как переменную экземпляра, прежде чем планировать таймер в цикле выполнения.

В вашем методе updateCountdownLabel:, как только ваше конечное условие будет выполнено, просто вызовите -invalidate в своем экземпляре таймера. Это удалит таймер из цикла выполнения, и, поскольку вы никогда его не сохраняли, он будет освобожден.

Я обновил методы, чтобы использовать NSTimer на основе селектора, а не NSInvocation на основе селектора. Это означает, что сигнатура метода обратного вызова определена так, как вы ожидаете. Это также позволяет избежать необходимости хранить объект NSTimer в ivar:

- (void)startCountDown
{

    NSTimer* timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateCountdownLabel:) userInfo:nil repeats:YES]
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}


- (void)updateCountdownLabel:(NSTImer*)timer
{
    if(thingsAreAllDone)
    {
        [timer invalidate];
    }
}
person Rob Keniger    schedule 08.07.2011
comment
Кажется, это не работает, где вы используете (id)anArg, что там действительно должно быть? Я всегда ставлю таймер. В этом случае у меня есть - (void) updateCountdownLabel:(NSTimer *) timer, никогда раньше не пробовал ставить что-то другое, но когда я делаю это, как я уже упоминал, всякий раз, когда я использую переменную таймера, я получаю предупреждение для локального объявления таймера скрывает переменная экземпляра. Для оператора if я просто проверяю, меньше ли метка или равна нулю. Этот код не выдает ошибку, но не останавливает обратный отсчет метки до отрицательных значений. Любые идеи? - person Elbimio; 09.07.2011
comment
Я обновил код, чтобы использовать NSTimer на основе селектора, который должен дать вам желаемый результат. - person Rob Keniger; 09.07.2011
comment
Нашел проблему. Мне просто нужна была переменная, чтобы сохранить число на этикетке как int, а затем использовать ЭТО в if. Спасибо! - person Elbimio; 09.07.2011
comment
Это работает только тогда, когда он запускает updateCountdownLabel в первый раз, и вы немедленно вызываете недействительность на таймере. Если он запускал updateCountdownLabel несколько раз, а затем решает сделать таймер недействительным, то либо он не будет удаляться из NSRunLoop, либо NSRunLoop имеет другой источник ввода за сценой. - person AndaluZ; 01.03.2019