Остановить executeSelector: withObject: afterDelay для цикла - PullRequest
1 голос
/ 06 марта 2012

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

 - (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 ]

3 голосов
/ 06 марта 2012

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

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

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

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

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

2 голосов
/ 06 марта 2012

Причина, по которой он не запускается каждые 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
}
...