Остановить executeSelector:withObject:afterDelay для цикла

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

 - (IBAction)methodName:(UIButton*)sender 
{
        [self loopMethod];
}

-(void) loopMethod
{

   for( int index = 0; index < loopLimit; index++ ) 
   {
        //code I want to execute
        [self performSelector:@selector(loopMethod) 
                   withObject:nil 
                   afterDelay:2.0];   
   }
}

Код просто зацикливается, хотя я сделал цикл for конечным. Я хочу, чтобы код выполнялся, приостанавливался на две секунды, а затем запускал цикл, пока int значение меньше, чем loopLimit Я установил.

Намекнули, что это performSelector:withObject:afterDelay: метод, возможно, не подходит для использования здесь, но я не уверен, почему или что лучше использовать здесь.

Какие-нибудь интересные предложения?

2 ответа

Решение

Здесь происходит то, что цикл работает как можно быстрее, и performSelector:... звонки происходят с такой скоростью. Затем, в 2.0001, 2.0004, 2.0010, ... секунд спустя, method вызывается.

Другое дело (теперь, когда вы отредактировали, чтобы прояснить, что performSelector:... в конечном итоге вызывает тот же метод, в котором он находится, является то, что значение вашего цикла index переменная не сохраняется между вызовами. Каждый раз loopMethod выполняется, код в цикле начинается с начала: index устанавливается на ноль и считает. Это означает, что каждый раз, когда метод запускается, вы в конечном итоге loopLimit новые вызовы ожидают, через 2 секунды Каждый из этих вызовов, в свою очередь, порождает новый набор и так далее до бесконечности.

Каждый запуск цикла на самом деле конечен, но цикл продолжает выполняться. Вам нужен какой-то способ сообщить о необходимости остановки цикла, и вы не можете сделать это полностью в методе цикла. Вы можете поставить счетчик (ваш index переменный) в ивар; это сделало бы его значение постоянным при обращении к loopMethod, но я думаю, что вы хотите изучить использованиеNSTimer что повторяется:

[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(method:) userInfo:nil repeats:YES];

Если вы вставите это в ивар, вы можете отследить, сколько раз он выстрелил, и остановить его позже. На SO уже есть несколько сообщений об обновлении текстовых полей в цикле с использованием таймера, подобного следующему: https://stackru.com/search?q=%5Bobjc%5D+update+text+field+timer

Причина, по которой он не запускается каждые 2 секунды, заключается в том, что вы проходите через цикл и снимаете этот селектор с задержкой в ​​2 секунды. Другими словами, между циклами нет задержки. Если бы мне пришлось угадать, это, вероятно, ждет 2 секунды, а затем срабатывает loopLimit раз, правильно?

Чтобы ваша функция работала так, как вы хотите, она должна быть рекурсивной.

-(void) methodName
{
   if(index < loopLimit) {
    //code you want to execute
    [self performSelector:@selector(**methodName**) withObject:nil afterDelay:2.0];   
   }
   index++;
}

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

В функции вы запускаете таймер следующим образом:

[self setIndex:0];
[self setTimer:[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(method:) userInfo:nil repeats:YES]];

тогда этот метод вызывается каждый раз:

-(void)method:(NSTimer *)timer {
    if(index >= loopLimit) {
         [[self timer] invalidate];
    }

    //Code you want to execute
}
Другие вопросы по тегам