Objective-C Programming_ The Big Nerd Ranch Guide - Aaron Hillegass [76]
int main (int argc, const char * argv[])
{
@autorelease {
NSString *string = @"Hello, World!";
NSLog(@"%@ has %d vowels", string, [string vowelCount]);
}
return 0;
}
Build and run the program. Nifty, eh? Categories turn out to be very useful.
It is important to note that only this program has the category. If you want the method available in another program, you must add the file to your project and compile the category in when you build that program.
32
Blocks
In Chapter 24, you learned about the callback mechanisms delegation and notifications. Callbacks allow other objects to call methods in your object in response to events. While perfectly functional, these approaches break up your code. Pieces of your program that you’d like to be close together for clarity’s sake usually aren’t.
For example, in your Callbacks program from Chapter 24, you added code to register your object for a notification when the user’s time zone changes and to set zoneChange: to be triggered when this notification is received. But now I’m reading your code and curious about what this zoneChange: method does when it is triggered, so I go looking for the implementation of this method. In the Callbacks example, the code that registers the object for a notification and the implementation of the method that is triggered are right next to each other, but you can imagine that in a larger, more complex application, these two pieces of code could be hundreds of lines away from each other.
Mac OS X 10.6 and iOS 4 introduced a new feature called blocks. An Objective-C block is just a chunk of code like a C function, but it can be passed around as data. We’ll see shortly how this keeps relevant code together.
Blocks and block syntax are definitely an advanced Objective-C topic and can be confusing at first. However, Apple’s APIs are using blocks more and more. In this chapter, we’ll step through a couple of simple examples so that you’ll be ready when you encounter blocks in the wild.
If you have a background in another programming language, you might know blocks as anonymous functions, closures, or lambdas. If you’re familiar with function pointers, blocks may appear to be similar, but you’ll soon see that proper use of blocks allows for more elegant code than can be written with function pointers.
Defining blocks
This is a block:
^{
NSLog(@"I'm a log statement within a block!");
}
This looks like a function, but it has a caret (^) instead of a function name. The caret identifies this bit of code as a block. Also, like a function, a block can take arguments:
^(double dividend, double divisor) {
double quotient = dividend / divisor;
return quotient;
}
This block takes two doubles as arguments. A block can have a return value as well, but we’ll come back to that.
Do these blocks have names? Not yet. These blocks are values, like the number 5 is a value. To be able to access a block by a name, we have to assign it to a block variable.
Using blocks
To see how this works, we’re going to dive right into some code. In this exercise, you’re going to use a block to remove all of the vowels from each of the strings in an array.
Create a new Foundation Command Line Tool and call it VowelMovement. In this program, you will use a block to iterate over an array of strings, transforming each one. First, you’re going to create three arrays: one to store the original strings, one to store the “devowelized” strings, and a third to store the characters to strip from the strings. In main.m, replace the code inside of the @autoreleasepool’s curly braces:
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: