Остановить 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
}