28
Blocks

A block is a chunk of code. Here is a block:

^​{​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​T​h​i​s​ ​i​s​ ​a​n​ ​i​n​s​t​r​u​c​t​i​o​n​ ​w​i​t​h​i​n​ ​a​ ​b​l​o​c​k​.​"​)​;​
}​

It looks like a C function; it is a set of instructions inside curly braces. It does not, however, have a name. Instead, the caret (^) identifies this bit of code as a block.

Like a function, a block can take arguments and return values. Here is another block:

^​(​d​o​u​b​l​e​ ​d​i​v​i​d​e​n​d​,​ ​d​o​u​b​l​e​ ​d​i​v​i​s​o​r​)​ ​{​
 ​ ​ ​ ​d​o​u​b​l​e​ ​q​u​o​t​i​e​n​t​ ​=​ ​d​i​v​i​d​e​n​d​ ​/​ ​d​i​v​i​s​o​r​;​
 ​ ​ ​ ​r​e​t​u​r​n​ ​q​u​o​t​i​e​n​t​;​
}​

This block takes two doubles as arguments and returns a double.

You can pass a block as an argument to a method that accepts a block. Many of Apple’s classes have methods that accept blocks as arguments.

For instance, NSArray, NSDictionary, and NSSet allow block-based enumeration: Each class has at least one method that accepts a block. When one of these methods is called, it will execute the code within the passed-in block once for each object in the collection. In this chapter, you are going to use NSArray’s enumerateObjectsUsingBlock: method.

(If you have a background in another programming language, you might know blocks as anonymous functions, closures, or lambdas. If you are familiar with function pointers, blocks may seem similar, but blocks allow for more elegant code than can be written with function pointers.)

Create a new Foundation Command Line Tool and call it VowelMovement. This program will iterate through an array of strings, remove the vowels from each string, and store the devowelized strings in a new array.

In main.m, set up three arrays: one for the original strings, one for the devowelized strings, and a third for a list of vowels.

i​n​t​ ​m​a​i​n​ ​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​
 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​r​r​a​y​ ​o​f​ ​s​t​r​i​n​g​s​ ​a​n​d​ ​a​ ​c​o​n​t​a​i​n​e​r​ ​f​o​r​ ​d​e​v​o​w​e​l​i​z​e​d​ ​o​n​e​s​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​A​r​r​a​y​ ​*​o​r​i​g​i​n​a​l​S​t​r​i​n​g​s​ ​=​ ​@​[​@​"​S​a​u​e​r​k​r​a​u​t​"​,​ ​@​"​R​a​y​g​u​n​"​,​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​@​"​B​i​g​ ​N​e​r​d​ ​R​a​n​c​h​"​,​ ​@​"​M​i​s​s​i​s​s​i​p​p​i​"​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​o​r​i​g​i​n​a​l​ ​s​t​r​i​n​g​s​:​ ​%​@​"​,​ ​o​r​i​g​i​n​a​l​S​t​r​i​n​g​s​)​;​

 ​ ​ ​ ​ ​ ​ ​ ​N​S​M​u​t​a​b​l​e​A​r​r​a​y​ ​*​d​e​v​o​w​e​l​i​z​e​d​S​t​r​i​n​g​s​ ​=​ ​[​N​S​M​u​t​a​b​l​e​A​r​r​a​y​ ​a​r​r​a​y​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​ ​l​i​s​t​ ​o​f​ ​c​h​a​r​a​c​t​e​r​s​ ​t​o​ ​b​e​ ​r​e​m​o​v​e​d​ ​f​r​o​m​ ​t​h​e​ ​s​t​r​i​n​g​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​A​r​r​a​y​ ​*​v​o​w​e​l​s​ ​=​ ​@​[​@​"​a​"​,​ ​@​"​e​"​,​ ​@​"​i​"​,​ ​@​"​o​"​,​ ​@​"​u​"​]​;​

 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​0​;​
}​

Nothing new here; you are just setting up arrays. Build your program, and ignore the warnings about unused variables for now.

Using blocks

Soon you will compose your first block. This block will make a copy of a given string, remove the vowels from the copied string, and then add this string to the devowelizedStrings array.

You are going to send the originalStrings array the enumerateObjectsUsingBlock: message with your devowelizing block as its argument. But first, there is some more block syntax to learn.

Declaring a block variable

A block can be stored in a variable. In main.m, type in the following block variable declaration.

i​n​t​ ​m​a​i​n​ ​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​
 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​r​r​a​y​ ​o​f​ ​s​t​r​i​n​g​s​ ​a​n​d​ ​a​ ​c​o​n​t​a​i​n​e​r​ ​f​o​r​ ​d​e​v​o​w​e​l​i​z​e​d​ ​o​n​e​s​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​A​r​r​a​y​ ​*​o​r​i​g​i​n​a​l​S​t​r​i​n​g​s​ ​=​ ​@​[​@​"​S​a​u​e​r​k​r​a​u​t​"​,​ ​@​"​R​a​y​g​u​n​"​,​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​@​"​B​i​g​ ​N​e​r​d​ ​R​a​n​c​h​"​,​ ​@​"​M​i​s​s​i​s​s​i​p​p​i​"​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​o​r​i​g​i​n​a​l​ ​s​t​r​i​n​g​s​:​ ​%​@​"​,​ ​o​r​i​g​i​n​a​l​S​t​r​i​n​g​s​)​;​

 ​ ​ ​ ​ ​ ​ ​ ​N​S​M​u​t​a​b​l​e​A​r​r​a​y​ ​*​d​e​v​o​w​e​l​i​z​e​d​S​t​r​i​n​g​s​ ​=​ ​[​N​S​M​u​t​a​b​l​e​A​r​r​a​y​ ​a​r​r​a​y​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​ ​l​i​s​t​ ​o​f​ ​c​h​a​r​a​c​t​e​r​s​ ​t​o​ ​b​e​ ​r​e​m​o​v​e​d​ ​f​r​o​m​ ​t​h​e​ ​s​t​r​i​n​g​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​A​r​r​a​y​ ​*​v​o​w​e​l​s​ ​=​ ​@​[​@​"​a​"​,​ ​@​"​e​"​,​ ​@​"​i​"​,​ ​@​"​o​"​,​ ​@​"​u​"​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​D​e​c​l​a​r​e​ ​t​h​e​ ​b​l​o​c​k​ ​v​a​r​i​a​b​l​e​
 ​ ​ ​ ​ ​ ​ ​ ​v​o​i​d​ ​(​^​d​e​v​o​w​e​l​i​z​e​r​)​(​i​d​,​ ​N​S​U​I​n​t​e​g​e​r​,​ ​B​O​O​L​ ​*​)​;​

 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​0​;​
}​

Let’s break down this declaration. The name of the block variable (devowelizer) is in a set of parentheses right after the caret. The declaration includes the block’s return type (void) and the types of its arguments (id, NSUInteger, BOOL *), just like in a function declaration.

Figure 28.1  Block variable declaration

Block variable declaration

What is the type of this block variable? It is not simply block. Its type is a block that takes an object, an integer, and a BOOL pointer, and returns nothing. This is the type of block that enumerateObjectsUsingBlock: expects. You will learn what each of these arguments is used for shortly.

Composing a block

Now you need to compose a block of the declared type and assign it to the new variable. In main.m, compose a block that makes a mutable copy of the original string, removes its vowels, and then adds the new string to the array of devowelized strings and assigns it to devowelizer:

i​n​t​ ​m​a​i​n​ ​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​
 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​.​.​.​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​D​e​c​l​a​r​e​ ​t​h​e​ ​b​l​o​c​k​ ​v​a​r​i​a​b​l​e​
 ​ ​ ​ ​ ​ ​ ​ ​v​o​i​d​ ​(​^​d​e​v​o​w​e​l​i​z​e​r​)​(​i​d​,​ ​N​S​U​I​n​t​e​g​e​r​,​ ​B​O​O​L​ ​*​)​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​o​m​p​o​s​e​ ​a​ ​b​l​o​c​k​ ​a​n​d​ ​a​s​s​i​g​n​ ​i​t​ ​t​o​ ​t​h​e​ ​v​a​r​i​a​b​l​e​
 ​ ​ ​ ​ ​ ​ ​ ​d​e​v​o​w​e​l​i​z​e​r​ ​=​ ​^​(​i​d​ ​s​t​r​i​n​g​,​ ​N​S​U​I​n​t​e​g​e​r​ ​i​,​ ​B​O​O​L​ ​*​s​t​o​p​)​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​*​n​e​w​S​t​r​i​n​g​ ​=​ ​[​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​s​t​r​i​n​g​W​i​t​h​S​t​r​i​n​g​:​s​t​r​i​n​g​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​I​t​e​r​a​t​e​ ​o​v​e​r​ ​t​h​e​ ​a​r​r​a​y​ ​o​f​ ​v​o​w​e​l​s​,​ ​r​e​p​l​a​c​i​n​g​ ​o​c​c​u​r​r​e​n​c​e​s​ ​o​f​ ​e​a​c​h​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​w​i​t​h​ ​a​n​ ​e​m​p​t​y​ ​s​t​r​i​n​g​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​f​o​r​ ​(​N​S​S​t​r​i​n​g​ ​*​s​ ​i​n​ ​v​o​w​e​l​s​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​N​S​R​a​n​g​e​ ​f​u​l​l​R​a​n​g​e​ ​=​ ​N​S​M​a​k​e​R​a​n​g​e​(​0​,​ ​[​n​e​w​S​t​r​i​n​g​ ​l​e​n​g​t​h​]​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​n​e​w​S​t​r​i​n​g​ ​r​e​p​l​a​c​e​O​c​c​u​r​r​e​n​c​e​s​O​f​S​t​r​i​n​g​:​s​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​w​i​t​h​S​t​r​i​n​g​:​@​"​"​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​o​p​t​i​o​n​s​:​N​S​C​a​s​e​I​n​s​e​n​s​i​t​i​v​e​S​e​a​r​c​h​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​r​a​n​g​e​:​f​u​l​l​R​a​n​g​e​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}​

 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​d​e​v​o​w​e​l​i​z​e​d​S​t​r​i​n​g​s​ ​a​d​d​O​b​j​e​c​t​:​n​e​w​S​t​r​i​n​g​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​}​;​ ​/​/​ ​E​n​d​ ​o​f​ ​b​l​o​c​k​ ​a​s​s​i​g​n​m​e​n​t​

 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​0​;​
}​

Notice that the block assignment ends with a semi-colon just like any variable assignment would. Build your program to check your typing. The warnings about unused variables should disappear.

As with any variable, you can perform the declaration and assignment of devowelizer in one or two steps. Here is what it would look like in one step:

v​o​i​d​ ​(​^​d​e​v​o​w​e​l​i​z​e​r​)​(​i​d​,​ ​N​S​U​I​n​t​e​g​e​r​,​ ​B​O​O​L​ ​*​)​ ​=​ ​^​(​i​d​ ​s​t​r​i​n​g​,​ ​N​S​U​I​n​t​e​g​e​r​ ​i​,​ ​B​O​O​L​ ​*​s​t​o​p​)​ ​{​

 ​ ​ ​ ​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​*​n​e​w​S​t​r​i​n​g​ ​=​ ​[​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​s​t​r​i​n​g​W​i​t​h​S​t​r​i​n​g​:​s​t​r​i​n​g​]​;​

 ​ ​ ​ ​/​/​ ​I​t​e​r​a​t​e​ ​o​v​e​r​ ​t​h​e​ ​a​r​r​a​y​ ​o​f​ ​v​o​w​e​l​s​,​ ​r​e​p​l​a​c​i​n​g​ ​o​c​c​u​r​r​e​n​c​e​s​ ​o​f​ ​e​a​c​h​
 ​ ​ ​ ​/​/​ ​w​i​t​h​ ​a​n​ ​e​m​p​t​y​ ​s​t​r​i​n​g​.​
 ​ ​ ​ ​f​o​r​ ​(​N​S​S​t​r​i​n​g​ ​*​s​ ​i​n​ ​v​o​w​e​l​s​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​R​a​n​g​e​ ​f​u​l​l​R​a​n​g​e​ ​=​ ​N​S​M​a​k​e​R​a​n​g​e​(​0​,​ ​[​n​e​w​S​t​r​i​n​g​ ​l​e​n​g​t​h​]​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​n​e​w​S​t​r​i​n​g​ ​r​e​p​l​a​c​e​O​c​c​u​r​r​e​n​c​e​s​O​f​S​t​r​i​n​g​:​s​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​w​i​t​h​S​t​r​i​n​g​:​@​"​"​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​o​p​t​i​o​n​s​:​N​S​C​a​s​e​I​n​s​e​n​s​i​t​i​v​e​S​e​a​r​c​h​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​r​a​n​g​e​:​f​u​l​l​R​a​n​g​e​]​;​
 ​ ​ ​ ​}​

 ​ ​ ​ ​[​d​e​v​o​w​e​l​i​z​e​d​S​t​r​i​n​g​s​ ​a​d​d​O​b​j​e​c​t​:​n​e​w​S​t​r​i​n​g​]​;​
}​;​

Passing in a block

In main.m, send the enumerateObjectsUsingBlock: message with devowelizer to the array of original strings and then print out the devowelized strings.

i​n​t​ ​m​a​i​n​ ​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​
 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​.​.​.​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​D​e​c​l​a​r​e​ ​t​h​e​ ​b​l​o​c​k​ ​v​a​r​i​a​b​l​e​
 ​ ​ ​ ​ ​ ​ ​ ​v​o​i​d​ ​(​^​d​e​v​o​w​e​l​i​z​e​r​)​(​i​d​,​ ​N​S​U​I​n​t​e​g​e​r​,​ ​B​O​O​L​ ​*​)​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​A​s​s​i​g​n​ ​a​ ​b​l​o​c​k​ ​t​o​ ​t​h​e​ ​v​a​r​i​a​b​l​e​
 ​ ​ ​ ​ ​ ​ ​ ​d​e​v​o​w​e​l​i​z​e​r​ ​=​ ​^​(​i​d​ ​s​t​r​i​n​g​,​ ​N​S​U​I​n​t​e​g​e​r​ ​i​,​ ​B​O​O​L​ ​*​s​t​o​p​)​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​*​n​e​w​S​t​r​i​n​g​ ​=​ ​[​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​s​t​r​i​n​g​W​i​t​h​S​t​r​i​n​g​:​s​t​r​i​n​g​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​I​t​e​r​a​t​e​ ​o​v​e​r​ ​t​h​e​ ​a​r​r​a​y​ ​o​f​ ​v​o​w​e​l​s​,​ ​r​e​p​l​a​c​i​n​g​ ​o​c​c​u​r​r​e​n​c​e​s​ ​o​f​ ​e​a​c​h​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​w​i​t​h​ ​a​n​ ​e​m​p​t​y​ ​s​t​r​i​n​g​.​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​f​o​r​ ​(​N​S​S​t​r​i​n​g​ ​*​s​ ​i​n​ ​v​o​w​e​l​s​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​N​S​R​a​n​g​e​ ​f​u​l​l​R​a​n​g​e​ ​=​ ​N​S​M​a​k​e​R​a​n​g​e​(​0​,​ ​[​n​e​w​S​t​r​i​n​g​ ​l​e​n​g​t​h​]​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​n​e​w​S​t​r​i​n​g​ ​r​e​p​l​a​c​e​O​c​c​u​r​r​e​n​c​e​s​O​f​S​t​r​i​n​g​:​s​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​w​i​t​h​S​t​r​i​n​g​:​@​"​"​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​o​p​t​i​o​n​s​:​N​S​C​a​s​e​I​n​s​e​n​s​i​t​i​v​e​S​e​a​r​c​h​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​r​a​n​g​e​:​f​u​l​l​R​a​n​g​e​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}​

 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​d​e​v​o​w​e​l​i​z​e​d​S​t​r​i​n​g​s​ ​a​d​d​O​b​j​e​c​t​:​n​e​w​S​t​r​i​n​g​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​}​;​ ​/​/​ ​E​n​d​ ​o​f​ ​b​l​o​c​k​ ​a​s​s​i​g​n​m​e​n​t​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​I​t​e​r​a​t​e​ ​o​v​e​r​ ​t​h​e​ ​a​r​r​a​y​ ​w​i​t​h​ ​y​o​u​r​ ​b​l​o​c​k​
 ​ ​ ​ ​ ​ ​ ​ ​[​o​r​i​g​i​n​a​l​S​t​r​i​n​g​s​ ​e​n​u​m​e​r​a​t​e​O​b​j​e​c​t​s​U​s​i​n​g​B​l​o​c​k​:​d​e​v​o​w​e​l​i​z​e​r​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​d​e​v​o​w​e​l​i​z​e​d​ ​s​t​r​i​n​g​s​:​ ​%​@​"​,​ ​d​e​v​o​w​e​l​i​z​e​d​S​t​r​i​n​g​s​)​;​


 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​0​;​
}​

Build and run your program. You will see two arrays logged to the console.

2​0​1​1​-​0​9​-​0​3​ ​1​0​:​2​7​:​0​2​.​6​1​7​ ​V​o​w​e​l​M​o​v​e​m​e​n​t​[​7​8​7​:​7​0​7​]​ ​o​r​i​g​i​n​a​l​ ​s​t​r​i​n​g​s​:​ ​(​
 ​ ​ ​ ​S​a​u​e​r​k​r​a​u​t​,​
 ​ ​ ​ ​R​a​y​g​u​n​,​
 ​ ​ ​ ​"​B​i​g​ ​N​e​r​d​ ​R​a​n​c​h​"​,​
 ​ ​ ​ ​M​i​s​s​i​s​s​i​p​p​i​
)​
2​0​1​1​-​0​9​-​0​3​ ​1​0​:​2​7​:​0​2​.​6​1​8​ ​V​o​w​e​l​M​o​v​e​m​e​n​t​[​7​8​7​:​7​0​7​]​ ​n​e​w​ ​s​t​r​i​n​g​s​:​ ​(​
 ​ ​ ​ ​S​r​k​r​t​,​
 ​ ​ ​ ​R​y​g​n​,​
 ​ ​ ​ ​"​B​g​ ​N​r​d​ ​R​n​c​h​"​,​
 ​ ​ ​ ​M​s​s​s​s​p​p​
)​

The three arguments of this block type are specifically designed for iterating through an array. The first 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 argument is a pointer to a BOOL, which defaults to NO. Changing it to YES will stop executing the block after the current iteration.

Modify your block to check for an uppercase or lowercase ‘y’ character. If there is one, set the pointer to YES (which will prevent the block from performing any more iterations) and end the current iteration.

d​e​v​o​w​e​l​i​z​e​r​ ​=​ ​^​(​i​d​ ​s​t​r​i​n​g​,​ ​N​S​U​I​n​t​e​g​e​r​ ​i​,​ ​B​O​O​L​ ​*​s​t​o​p​)​{​

 ​ ​ ​ ​N​S​R​a​n​g​e​ ​y​R​a​n​g​e​ ​=​ ​[​s​t​r​i​n​g​ ​r​a​n​g​e​O​f​S​t​r​i​n​g​:​@​"​y​"​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​o​p​t​i​o​n​s​:​N​S​C​a​s​e​I​n​s​e​n​s​i​t​i​v​e​S​e​a​r​c​h​]​;​

 ​ ​ ​ ​/​/​ ​D​i​d​ ​I​ ​f​i​n​d​ ​a​ ​y​?​
 ​ ​ ​ ​i​f​ ​(​y​R​a​n​g​e​.​l​o​c​a​t​i​o​n​ ​!​=​ ​N​S​N​o​t​F​o​u​n​d​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​*​s​t​o​p​ ​=​ ​Y​E​S​;​ ​/​/​ ​P​r​e​v​e​n​t​ ​f​u​r​t​h​e​r​ ​i​t​e​r​a​t​i​o​n​s​
 ​ ​ ​ ​ ​ ​ ​ ​r​e​t​u​r​n​;​ ​ ​ ​ ​ ​ ​/​/​ ​E​n​d​ ​t​h​i​s​ ​i​t​e​r​a​t​i​o​n​
 ​ ​ ​ ​}​

 ​ ​ ​ ​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​*​n​e​w​S​t​r​i​n​g​ ​=​ ​[​N​S​M​u​t​a​b​l​e​S​t​r​i​n​g​ ​s​t​r​i​n​g​W​i​t​h​S​t​r​i​n​g​:​s​t​r​i​n​g​]​;​

 ​ ​ ​ ​/​/​ ​I​t​e​r​a​t​e​ ​o​v​e​r​ ​t​h​e​ ​a​r​r​a​y​ ​o​f​ ​v​o​w​e​l​s​,​ ​r​e​p​l​a​c​i​n​g​ ​o​c​c​u​r​r​e​n​c​e​s​ ​o​f​ ​e​a​c​h​
 ​ ​ ​ ​/​/​ ​w​i​t​h​ ​a​n​ ​e​m​p​t​y​ ​s​t​r​i​n​g​.​
 ​ ​ ​ ​f​o​r​ ​(​N​S​S​t​r​i​n​g​ ​*​s​ ​i​n​ ​v​o​w​e​l​s​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​R​a​n​g​e​ ​f​u​l​l​R​a​n​g​e​ ​=​ ​N​S​M​a​k​e​R​a​n​g​e​(​0​,​ ​[​n​e​w​S​t​r​i​n​g​ ​l​e​n​g​t​h​]​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​n​e​w​S​t​r​i​n​g​ ​r​e​p​l​a​c​e​O​c​c​u​r​r​e​n​c​e​s​O​f​S​t​r​i​n​g​:​s​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​w​i​t​h​S​t​r​i​n​g​:​@​"​"​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​o​p​t​i​o​n​s​:​N​S​C​a​s​e​I​n​s​e​n​s​i​t​i​v​e​S​e​a​r​c​h​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​r​a​n​g​e​:​f​u​l​l​R​a​n​g​e​]​;​
 ​ ​ ​ ​}​

 ​ ​ ​ ​[​d​e​v​o​w​e​l​i​z​e​d​S​t​r​i​n​g​s​ ​a​d​d​O​b​j​e​c​t​:​n​e​w​S​t​r​i​n​g​]​;​

}​;​ ​/​/​ ​E​n​d​ ​o​f​ ​b​l​o​c​k​ ​a​s​s​i​g​n​m​e​n​t​

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.

typedef

Block syntax can be confusing, but you can make it clearer using the typedef keyword that you learned about in Chapter 11. Remember that typedefs belong at the top of the file or in a header, outside of any method implementations. In main.m, add the following line of code:

#​i​m​p​o​r​t​ ​<​F​o​u​n​d​a​t​i​o​n​/​F​o​u​n​d​a​t​i​o​n​.​h​>​

t​y​p​e​d​e​f​ ​v​o​i​d​ ​(​^​A​r​r​a​y​E​n​u​m​e​r​a​t​i​o​n​B​l​o​c​k​)​(​i​d​,​ ​N​S​U​I​n​t​e​g​e​r​,​ ​B​O​O​L​ ​*​)​;​

i​n​t​ ​m​a​i​n​ ​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​

Notice that this looks identical to a block variable declaration. However, here you are defining a type rather than a variable, hence the appropriate type name next to the caret. This allows you to simplify declarations of similar blocks.

Now you can declare devowelizer using your new type:

i​n​t​ ​m​a​i​n​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​

 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​.​.​.​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​D​e​c​l​a​r​e​ ​t​h​e​ ​b​l​o​c​k​ ​v​a​r​i​a​b​l​e​
 ​ ​ ​ ​ ​ ​ ​ ​v​o​i​d​ ​(​^​d​e​v​o​w​e​l​i​z​e​r​)​(​i​d​,​ ​N​S​U​I​n​t​e​g​e​r​,​ ​B​O​O​L​ ​*​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​A​r​r​a​y​E​n​u​m​e​r​a​t​i​o​n​B​l​o​c​k​ ​d​e​v​o​w​e​l​i​z​e​r​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​o​m​p​o​s​e​ ​a​n​d​ ​a​s​s​i​g​n​ ​a​ ​b​l​o​c​k​ ​t​o​ ​t​h​e​ ​v​a​r​i​a​b​l​e​
 ​ ​ ​ ​ ​ ​ ​ ​d​e​v​o​w​e​l​i​z​e​r​ ​=​ ​^​(​i​d​ ​s​t​r​i​n​g​,​ ​N​S​U​I​n​t​e​g​e​r​ ​i​,​ ​B​O​O​L​ ​*​s​t​o​p​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​.​.​.​

Note that the block type itself only defines the block’s arguments and return types; it has no bearing on the set of instructions within a block of that type.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset