bdv
bdv

Reputation: 1204

break out of loop that's being enumerated

I want to break out of a loop that's being enumerated.

Here's an example of my problem:

for(NSArray *x in retrieved_data){

  for(NSDictionary *someJson in array_that_is_enumerated){

     if(intersection_of_retrieved_data_indicates_deletion_in_array){
         [array_that_is_being_enumerated removeObject:someJson];

         // can't call return; here: it's important outer for loop finishes.
         // break; will only have effect in this scope

     } else {// perform other logic}
  }

}

How can I still delete this object and jump to the first for/in loop again?

Upvotes: 0

Views: 90

Answers (2)

CRD
CRD

Reputation: 53000

A break terminates the closest enclosing loop, so a break in your if moves to the next iteration of your outer loop, which from:

can't call return; here: it's important outer for loop finishes

appears to be exactly what you want.

Terminating multiple nested loops can be messy, you can do things like: use a label and goto; set a flag to test in each loop; or wrap the loops in a function/method/block and return.

HTH

Addendum

There appears to be some concern in comments/answers about deleting while enumerating, while this is completely correct you can delete within an enumerating loop provided you then terminate the loop - it is proceeding to the next iteration which is not allowed. So what the OP is doing, a test-delete-break, is perfectly OK.

After Comment

Following on from addendum, here is some sample code:

NSArray *outer = @[@"one", @"three", @"dog"];

NSMutableArray *inner = @[@"one", @"two", @"cat", @"dog"].mutableCopy;

NSLog(@"Before: %@", inner);
for (NSString *wordToDelete in outer)
{
   NSLog(@"Consider: %@", wordToDelete);
   for (NSString *item in inner)
   {
      if ([item isEqualToString:wordToDelete])
      {
         NSLog(@"Removing and breaking");
         [inner removeObject:item];
         break;
      }
   }
   // break lands here
}
NSLog(@"After: %@", inner);

The final result is @[ @"two", @"cat" ]. The inner loop terminates and the outer one completes. It is legitimate to do this, what would be incorrect would be doing an iteration after inner was modified.

Upvotes: 2

danh
danh

Reputation: 62686

I think you can get what you want without break. It seems the job of that inner loop is to identify elements in array_that_is_enumerated that should be deleted, and that decision depends on the elements in retrieved_data.

@Agressor is right that you cannot delete while enumerating, so how about isolating the deletion condition in a function?

// this could be done neatly as an NSPredicate, too
- (NSDictionary *)itemInInnerArrayThatShouldBeDeleted:(NSArray *)xFromRetrievedData {
    for (NSDictionary *someJson in array_that_is_enumerated) {
        if (intersection_of_retrieved_data_indicates_deletion_in_array) {
            return someJson;
        }
    }
    return nil;
}

Now your outer loop collects elements to be deleted as follows:

NSMutableArray *deleteThese = [NSMutableArray array];

for (NSArray *x in retrieved_data) {
    NSDictionary *someJson = [self itemInInnerArrayThatShouldBeDeleted:x];
    if (someJson) [deleteThese addObject:someJson];
}
// now that we are done enumerating, we can safely delete
[array_that_is_enumerated removeObjectsInArray:deleteThese];

Upvotes: 0

Related Questions