Continue
Last week we
looked at how to end a loop early using the break
keyword.
Today we will look at a similar action: how to skip to the next
iteration.
Sometimes you need to process each item in a collection or sequence,
but some of those items get full processing and some don't. For
example, you may want to skip empty strings in a collection.
Frequently you do this using an if...else
statement:
NSArray *collection = [NSArray arrayWithObjects: @"foo", @"", @"bar", @"baz", @"", nil];
int wordCount = 0;
for (NSString *item in collection) {
NSLog(@"found '%@'", item);
if (item.length > 0) {
wordCount++;
}
}
NSLog(@"word count = %d", wordCount);
This is generally a good approach, but sometimes you have complex
nested logic:
NSArray *collection = [NSArray arrayWithObjects: @"foo", @"\n", @"bar", @"baz", @"", nil];
int wordCount = 0;
for (NSString *item in collection) {
NSLog(@"found '%@'", item);
if (item.length > 0) {
if ( ! [item isEqualToString:@"\n"]) {
wordCount++;
if (item.length < 4) {
NSLog(@"short word");
} else {
NSLog(@"long word");
}
}
}
}
NSLog(@"word count = %d", wordCount);
The continue
statement can help you simplify complicated
cases like this by stopping the execution of the loop body for the
current item and advancing to the next. Using continue
,
we can rewrite the example like this:
NSArray *collection = [NSArray arrayWithObjects: @"foo", @"\n", @"bar", @"baz", @"", nil];
int wordCount = 0;
for (NSString *item in collection) {
NSLog(@"found '%@'", item);
if (item.length > 0) continue;
if ([@item isEqualToString:"\n"]) continue;
wordCount++;
if (item.length < 4) {
NSLog(@"short word");
} else {
NSLog(@"long word");
}
}
NSLog(@"word count = %d", wordCount);
Like break
, a continue
statement only works
on the innermost loop that encloses it:
// outer loop
for (int i = 0; i < 10; i++) { // loop A
if (...) continue; // skips to next item in A
// inner loop
for (int j = 0; j < 10; j++) { // loop B
if (...) continue; // skips to next item in B
}
if (...) continue; // skips to next item in A
}
The continue
statement is most useful with a
for
or for...in
loop, but can be used with a
while
and do...while
loop with care. It's
easy to create an infinite while
loop using
continue
:
NSArray *collection = [NSArray arrayWithObjects: @"foo", @"", @"bar", @"baz", @"", nil];
int wordCount = 0;
int i = 0;
while (i < collection.count) {
NSString *item = [collection objectAtIndex:i];
NSLog(@"found '%@'", item);
if (item.length > 0) {
continue; // OOPS! forgot to increment i
}
wordCount++;
i++;
}
NSLog(@"word count = %d", wordCount);
This loop will reach the second item in the collection and get stuck
there -- it never reaches the i++
at the end of the loop
body. The solution is simple:
NSArray *collection = [NSArray arrayWithObjects: @"foo", @"", @"bar", @"baz", @"", nil];
int wordCount = 0;
int i = 0;
while (i < collection.count) {
NSString *item = [collection objectAtIndex:i];
NSLog(@"found '%@'", item);
if (item.length > 0) {
i++;; // move to next item
continue;
}
wordCount++;
i++;
}
NSLog(@"word count = %d", wordCount);
This is a consequence of the free-form nature of the while
and do...while
loops. The compiler knows how to make a
for
or for...in
loop advance to the next
item, but the other loops leave that up to you; continue
acts more like a special goto
statement with
while
and do...while
loops.
Next time, we'll look at
the mother of all loops, the goto
statement.