1.11. Implementing while Loops

Problem

You want to let a piece of code run over and over again until a certain condition is met.

Solution

Use while loops and specify your exit condition. Here is the format for the while loop:

while (condition){
  CODE
}

Note

As long as the condition is a value other than zero/nil/NULL, the while loop will run.

Discussion

The while loop is the arrogant brother of the for loop (see Recipe 1.10) because while loops only take a condition that should be met for the loop to run. If the condition is positive, the loop will always run until the condition becomes negative. For instance, a while loop could be implemented to make an icon in the Dock in Mac OS X jump up and down until the user taps on that icon (this is actually a very bad user experience; icons in the Dock shouldn’t jump up and down continuously, but for a short interval, or even a fixed number of times, usually 3). The exit condition for the while loop is the user’s tapping on that icon. As long as the user hasn’t tapped on the icon, the icon will jump up and down.

A while loop is awkward to use with a counter because of its syntax. If you require a counter to control your loop, it is better to use a for loop. If you do require a while loop but still want to have access to a counter, you will need to manage the counter manually, like so:

NSUInteger counter = 0;
while (counter < 10){
  NSLog(@"Counter = %lu", (unsigned long)counter);
  counter++;
}

Just as you can have positive conditions for your while loops, you can have negative conditions as well:

BOOL shouldExitLoop = NO;
NSUInteger counter = 0;

while (shouldExitLoop == NO){
       counter++;
  if (counter >= 10){
    shouldExitLoop = YES;
  }
}

NSLog(@"Counter = %lu", (unsigned long)counter);

The output of this program is:

Counter = 10

So what we are doing is simply running a loop for as long as our counter is less than 10. If the value of the counter (adjusted inside the loop itself) goes over or becomes equal to 10, then we exit our loop. Just like a for loop, you can create an infinite loop using a while loop, although this is a terrible programming practice and you should avoid it by all means:

while (YES){
  /* Infinite loop */
}

You must make sure that you have an exit strategy in your while and for loops. For this, you need to keep an eye on the condition for your loops and make sure that the condition will be met at some point without making your loops hog all the memory and/or system resources while they run, while using autorelease objects. As you know, an autorelease object only gets released when the autorelease pool owning that object gets drained or released. If you do not have an autorelease pool inside your loop continuously releasing autorelease objects, your loop might end up consuming too much memory and your app might get terminated by iOS.

Here is another usage of a while loop:

char *myString = "Some Random String";
NSUInteger counter = 0;
char character;
while ((character = myString[counter++]) != 'R' &&
       counter < strlen(myString)){
  /* Empty */
}
NSLog(@"Found the letter R at character #%lu", (unsigned long)counter+1);

Here we are searching inside a string for the first occurrence of the letter R. As soon as we find it, we exit our while loop. We have included another condition: if we reach the end of the string (strlen(myString)), we end the loop, so we don’t wander off into undefined memory and cause a crash or a security flaw. (This is called a buffer overflow.)

This algorithm has a bug, however: it returns a wrong results when the letter R isn’t in the string at all. Because the while loop finishes when we get to the end of the string, we always print a message to the console saying that the letter R was found at some index. I will leave it up to you to fix this algorithm. As a hint, you might want to use a Boolean value when you do find the letter R and then later use that flag to determine whether the letter was found. To use that boolean technique, you might need to change the way the while loop is set up, but I think you get the idea.

A while loop is useful for traversing an array. For instance, a C String is an array of characters ending with a zero byte. If you are searching for a specific character in this array, you can simply write a while loop that starts from the first character and runs until it finds the zero terminator that ends the string. Here is an example:

char *cString = "My String";
char *stringPointer = cString;
while (*stringPointer != 0x00){
  NSLog(@"%c", *stringPointer);
  stringPointer++;
}

This example will print all the characters inside the string until it gets to the zero terminator of the string. Using a while loop, you can even create a function similar to the strlen() function that is able to find the length of a C String, like so:

NSUInteger lengthOfCString(const char *paramString){

  NSUInteger result = 0;

  if (paramString == NULL){
    return 0;
  }

  char *stringPointer = (char *)paramString;

  while (*stringPointer != 0x00){
    result++;
    stringPointer++;
  }

  return result;

}

Note

It’s better to use the built-in strlen for two reasons: it has been optimized to make the best use of the underlying hardware, and it’s less likely to contain a bug.

See Also

Recipe 1.10

Get iOS 6 Programming Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.