Objective-C Programming_ The Big Nerd Ranch Guide - Aaron Hillegass [78]
In main.m, add the following code to call enumerateObjectsUsingBlock: with devowelizer and then print out the devowelized strings.
int main (int argc, const char * argv[])
{
@autoreleasepool {
// Create the array of strings to devowelize and a container for new ones
NSArray *oldStrings = [NSArray arrayWithObjects:
@"Sauerkraut", @"Raygun", @"Big Nerd Ranch", @"Mississippi", nil];
NSLog(@"old strings: %@", oldStrings);
NSMutableArray *newStrings = [NSMutableArray array];
// Create a list of characters that we'll remove from the string
NSArray *vowels = [NSArray arrayWithObjects:
@"a", @"e", @"i", @"o", @"u", nil];
// Declare the block variable
void (^devowelizer)(id, NSUInteger, BOOL *);
// Assign a block to the variable
devowelizer = ^(id string, NSUInteger i, BOOL *stop) {
NSMutableString *newString = [NSMutableString stringWithString:string];
// Iterate over the array of vowels, replacing occurrences of each
// with an empty string.
for (NSString *s in vowels) {
NSRange fullRange = NSMakeRange(0, [newString length]);
[newString replaceOccurrencesOfString:s
withString:@""
options:NSCaseInsensitiveSearch
range:fullRange];
}
[newStrings addObject:newString];
}; // End of block assignment
// Iterate over the array with our block
[oldStrings enumerateObjectsUsingBlock:devowelizer];
NSLog(@"new strings: %@", newStrings);
}
return 0;
}
Build and run your program. You’ll see two arrays logged to the console. The second array should match the first array – without all those pesky vowels.
2011-09-03 10:27:02.617 VowelMovement[787:707] old strings: (
Sauerkraut,
Raygun,
"Big Nerd Ranch",
Mississippi
)
2011-09-03 10:27:02.618 VowelMovement[787:707] new strings: (
Srkrt,
Rygn,
"Bg Nrd Rnch",
Msssspp
)
It’s important to note that enumerateObjectsUsingBlock: won’t accept just any block as its argument. This method requires “a block that takes an object, an integer, and a BOOL pointer and returns nothing.” That’s why we constructed the block that we assigned to devowelizer as we did. Its three arguments are specifically designed for going through an array.
The first argument is a pointer to the current object. Notice that this pointer’s type is id so that it will work no matter what kind of objects the array contains. The second argument is an NSUInteger that is the index of the current object. The third object is a pointer to a BOOL, which defaults to NO. We can change it to YES if we want the array to stop after the current iteration.
Add a check at the beginning of the block assignment:
devowelizer = ^(id string, NSUInteger i, BOOL *stop){
NSRange yRange = [string rangeOfString:@"y"
options:NSCaseInsensitiveSearch];
// Did I find a y?
if (yRange.location != NSNotFound) {
*stop = YES; // Prevent further iterations
return; // Stop this iteration
}
NSMutableString *newString = [NSMutableString stringWithString:string];
// Iterate over the array of vowels, replacing occurrences of each
// with an empty string.
for (NSString *s in vowels) {
NSRange fullRange = NSMakeRange(0, [newString length]);
[newString replaceOccurrencesOfString:s
withString:@""
options:NSCaseInsensitiveSearch
range:fullRange];
}
[newStrings addObject:newString];
}; // End of block assignment
This will check to see if the string for the current iteration contains an uppercase or lowercase ‘y’ character. If it does, the pointer is set to YES (which will prevent the block from performing any more iterations) and then the current iteration is halted.
Build and run the program. Again, two arrays are logged to the debugger output, but this time, the array enumeration was cancelled during the second iteration when the block encountered a word with the letter ‘y’ in it. All you get is Srkrt.
Now that you’ve had some practice with blocks, let’s return to how blocks help solve the problem