it-swarm.com.ru

Как вырваться из двух вложенных циклов for в Objective-C?

У меня есть два для вложенных циклов, как это:

for(...) {
    for(...) {

    }
}

Я знаю, что есть оператор break. Но меня смущает, сломает ли она обе петли или только ту, в которой она была вызвана? Мне нужно сломать оба, как только я увижу, что нет смысла повторять больше раз.

73
Thanks

break прерывает один цикл, но вы можете добавить проверку к внешнему циклу, которая прерывается при разрыве внутреннего цикла.

bool dobreak = false;
for ( ..; !dobreak && ..; .. ) {
   for ( ... ) {
      if (...) {
         dobreak = true;
         break;
      }
   }
}
91
jbasko

Если использование goto упрощает код, то это будет уместно.

for (;;) 
{
    for (;;) 
    {
        break; /* breaks inner loop */
    } 
    for (;;) 
    {
        goto outer; /* breaks outer loop */
    }
} 
outer:;
105
Ori Pessach

Оператор break только выводит вас из внутреннего цикла. Если вам не нужны дополнительные издержки в коде, памяти и производительности выделенной переменной состояния, я рекомендую преобразовать код в собственную функцию или метод и использовать return для выхода из всех циклов:

void do_lots_of_work(void)
{
  int i, j;

  for(i=0; i<10 ; i++)
  {
    for(j=0;j< 10; j++)
    {
     ..
     ..
     if(disaster_struck())
      return; /* Gets us out of the loops, and the function too. */
    }
  }
}
13
unwind

Кроме уже упомянутой переменной-флага или goto вы можете throw исключение Objective-C:

@try {
  for() {
    for() {
       @throw ...
    }
  }
}
@catch{
  ...
}
9
lothar

Другие упоминали, как вы можете установить флаг или использовать goto, но я бы порекомендовал рефакторинг вашего кода, чтобы внутренний цикл превратился в отдельный метод. Этот метод может затем вернуть некоторый флаг, чтобы указать, что внешний цикл должен break. Если вы правильно называете свои методы, это гораздо более читабельно.

for (int i = 0; i < 10; i++) {
   if (timeToStop(i)) break;
}

-(bool) timeToStop: (int) i {
    for (int j = 0; j < 10; j++) {
        if (somethingBadHappens) return true;
    }

    return false;
}

Псевдокод, не проверен, но вы поняли.

7
George Armhold

Изменить счетчик верхней петли до перерыва

for(i=0; i<10 ; i++)
  for(j=0;j< 10; j++){
     ..
     ..
     i = 10; 
     break;
  }
2
oxigen

Другое решение состоит в том, чтобы выделить второй цикл в функции:

int i;

for(i=0; i<10 ; i++){
    if !innerLoop(i) {
        break;
    }
}

bool innerLoop(int i)
    int j;
    for(j=0;j< 10; j++){
        doSomthing(i,j);
        if(endcondtion){
            return false;
        }
    }
}
2
Martijn

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

bool isTerminated = false;

for (...)
{
    if (!isTerminated)
    {
        for(...)
        {
            ...

            isTerminated = true;
            break;
        }
    }
    else
    {
        break;
    }
}
2
Nick Allen

Вероятно, самый простой способ - использовать переменную flag 

for(i=0; i<10 && (done==false); i++)
  for(j=0;j< 10; j++){
     ..
     ..
     if(...){done=true; break;}
  }
2
Yogi

Оператор break выходит из внутреннего цикла. Для выхода из внешнего цикла потребуется дополнительный оператор test и break.

1
Lance Richardson

Если разрыв выполняется из набора вложенных циклов, прерывается только самый внутренний цикл, в котором выполняется разрыв. (Так же, как стандартный C)

0
Mitch Wheat

Просто ради ухмылки, как насчет того, чтобы изменить эту проверку истинности/ложности на метод и использовать операторы return:

- (bool) checkTrueFalse: parameters{

   for ( ...) {
      for ( ... ) {

         if (...) {
            return true;
         }

      }
   }
   return false;
}
0
Tom Howard

Точно так же, как последние, как правило, так:

for(i=0;i<a;i++){  
 for(j=0;j<a;j++){
  if(Something_goes_wrong){
   i=a;
   break;
   }
 }
}
0
Martin