More on blocks

Here are some other things you can do with blocks.

Return values

The block that you created for VowelMovement does not have a return value, but many blocks will. When a block returns a value, you can get the return value by calling the block variable like a function.

Let’s look again at one of the sample blocks you saw at the beginning of the chapter:

^​(​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 and returns a double. To store this block in a variable, you would declare a variable of that type and assign the block to it:

/​/​ ​D​e​c​l​a​r​e​ ​d​i​v​B​l​o​c​k​ ​v​a​r​i​a​b​l​e​
d​o​u​b​l​e​ ​(​^​d​i​v​B​l​o​c​k​)​(​d​o​u​b​l​e​,​d​o​u​b​l​e​)​;​

/​/​ ​A​s​s​i​g​n​ ​b​l​o​c​k​ ​t​o​ ​v​a​r​i​a​b​l​e​
d​i​v​B​l​o​c​k​ ​=​ ​^​(​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​;​
}​

You can then call divBlock like a function to get its return value:

d​o​u​b​l​e​ ​m​y​Q​u​o​t​i​e​n​t​ ​=​ ​d​i​v​B​l​o​c​k​(​4​2​.​0​,​ ​1​2​.​5​)​;​

Anonymous blocks

An anonymous block is a block that you pass directly to a method without assigning it to a block variable first.

Let’s consider the case of an anonymous integer first. When you want to pass an integer to a method, you have three options:

/​/​ ​O​p​t​i​o​n​ ​1​:​ ​T​o​t​a​l​l​y​ ​b​r​e​a​k​ ​i​t​ ​d​o​w​n​
i​n​t​ ​i​;​
i​ ​=​ ​5​;​
N​S​N​u​m​b​e​r​ ​*​n​u​m​ ​=​ ​[​N​S​N​u​m​b​e​r​ ​n​u​m​b​e​r​W​i​t​h​I​n​t​:​i​]​;​

/​/​ ​O​p​t​i​o​n​ ​2​:​ ​D​e​c​l​a​r​e​ ​a​n​d​ ​a​s​s​i​g​n​ ​o​n​ ​o​n​e​ ​l​i​n​e​
i​n​t​ ​i​ ​=​ ​5​;​
N​S​N​u​m​b​e​r​ ​*​n​u​m​ ​=​ ​[​N​S​N​u​m​b​e​r​ ​n​u​m​b​e​r​W​i​t​h​I​n​t​:​i​]​;​

/​/​ ​O​p​t​i​o​n​ ​3​:​ ​S​k​i​p​ ​t​h​e​ ​v​a​r​i​a​b​l​e​ ​e​n​t​i​r​e​l​y​
N​S​N​u​m​b​e​r​ ​*​n​u​m​ ​=​ ​[​N​S​N​u​m​b​e​r​ ​n​u​m​b​e​r​W​i​t​h​I​n​t​:​5​]​;​

If you take the third option, you are passing the integer anonymously. It is anonymous because it does not have a name (or a variable) associated with it.

You have the same options when you want to pass a block to a method. Currently, your code puts the block declaration, assignment, and usage on three separate lines of code. But it is more common to pass blocks anonymously. The first challenge at the end of this chapter is to modify the VowelMovement program to use an anonymous block.

External variables

A block typically uses other variables (both primitive variables and pointers to objects) that were created outside of the block. These are called external variables. To make sure that they will be available for as long as the block needs them, these variables are captured by the block.

For primitive variables, the values are copied and stored as local variables within the block. For pointers, the block will keep a strong reference to the objects it references. This means that any objects referred to by the block are guaranteed to live as long as the block itself. (If you have been wondering about the difference between blocks and function pointers, it is right here. Let’s see a function pointer do that!)

Using self in blocks

If you need to write a block that uses self, you must take a couple of extra steps to avoid a strong reference cycle. Consider an example where an instance of BNREmployee creates a block that will log the BNREmployee instance each time it executes:

m​y​B​l​o​c​k​ ​=​ ​^​{​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​:​ ​%​@​"​,​ ​s​e​l​f​)​;​
}​;​

The BNREmployee instance has a pointer to a block (myBlock). The block captures self, so it has a pointer back to the BNREmployee instance. You have a strong reference cycle.

To break the strong reference cycle, you declare a __weak pointer outside the block that points to self. Then you can use this pointer inside the block instead of self:

_​_​w​e​a​k​ ​B​N​R​E​m​p​l​o​y​e​e​ ​*​w​e​a​k​S​e​l​f​ ​=​ ​s​e​l​f​;​ ​/​/​ ​a​ ​w​e​a​k​ ​r​e​f​e​r​e​n​c​e​
m​y​B​l​o​c​k​ ​=​ ​^​{​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​:​ ​%​@​"​,​ ​w​e​a​k​S​e​l​f​)​;​
}​;​

The block’s reference to the BNREmployee instance is now a weak one, and the strong reference cycle is broken.

However, because the reference is weak, the object that self points to could be deallocated while the block is executing.

You can eliminate this risk by creating a strong local reference to self inside the block:

_​_​w​e​a​k​ ​B​N​R​E​m​p​l​o​y​e​e​ ​*​w​e​a​k​S​e​l​f​ ​=​ ​s​e​l​f​;​ ​/​/​ ​a​ ​w​e​a​k​ ​r​e​f​e​r​e​n​c​e​
m​y​B​l​o​c​k​ ​=​ ​^​{​
 ​ ​ ​ ​B​N​R​E​m​p​l​o​y​e​e​ ​*​i​n​n​e​r​S​e​l​f​ ​=​ ​w​e​a​k​S​e​l​f​;​ ​/​/​ ​a​ ​b​l​o​c​k​-​l​o​c​a​l​ ​s​t​r​o​n​g​ ​r​e​f​e​r​e​n​c​e​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​:​ ​%​@​"​,​ ​i​n​n​e​r​S​e​l​f​)​;​
}​;​

By creating the strong innerSelf reference, you have again created a strong reference cycle between the block and the BNREmployee instance. But because the innerSelf reference is local to the scope of the block, the strong reference cycle will only exist while the block is executing and will be broken automatically when the block ends.

This is good programming practice whenever you write a block that must reference self.

Unexpectedly using self in blocks

If you use an instance variable directly within a block, the block will capture self instead of the instance variable. This is because of a little-known nuance of instance variables. Consider this code that accesses an instance variable directly:

_​_​w​e​a​k​ ​B​N​R​E​m​p​l​o​y​e​e​ ​*​w​e​a​k​S​e​l​f​ ​=​ ​s​e​l​f​;​
m​y​B​l​o​c​k​ ​=​ ​^​{​
 ​ ​ ​ ​B​N​R​E​m​p​l​o​y​e​e​ ​*​i​n​n​e​r​S​e​l​f​ ​=​ ​w​e​a​k​S​e​l​f​;​ ​/​/​ ​a​ ​b​l​o​c​k​-​l​o​c​a​l​ ​s​t​r​o​n​g​ ​r​e​f​e​r​e​n​c​e​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​:​ ​%​@​"​,​ ​i​n​n​e​r​S​e​l​f​)​;​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​ ​I​D​:​ ​%​d​"​,​ ​_​e​m​p​l​o​y​e​e​I​D​)​;​
}​;​

The compiler interprets the direct variable access like this:

_​_​w​e​a​k​ ​B​N​R​E​m​p​l​o​y​e​e​ ​*​w​e​a​k​S​e​l​f​ ​=​ ​s​e​l​f​;​
m​y​B​l​o​c​k​ ​=​ ​^​{​
 ​ ​ ​ ​B​N​R​E​m​p​l​o​y​e​e​ ​*​i​n​n​e​r​S​e​l​f​ ​=​ ​w​e​a​k​S​e​l​f​;​ ​/​/​ ​a​ ​b​l​o​c​k​-​l​o​c​a​l​ ​s​t​r​o​n​g​ ​r​e​f​e​r​e​n​c​e​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​:​ ​%​@​"​,​ ​i​n​n​e​r​S​e​l​f​)​;​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​ ​I​D​:​ ​%​d​"​,​ ​s​e​l​f​-​>​_​e​m​p​l​o​y​e​e​I​D​)​;​
}​;​

Does the -> syntax look familiar? It is the syntax for accessing the member of a struct on the heap. At their deepest darkest cores, objects are actually structs.

Because the compiler reads _employeeID as self->_employeeID, self is unexpectedly captured by the block. This will cause the same strong reference cycle that you avoided with the use of weakSelf and innerSelf.

The fix? Don’t access instance variables directly. Use your accessors!

_​_​w​e​a​k​ ​B​N​R​E​m​p​l​o​y​e​e​ ​*​w​e​a​k​S​e​l​f​ ​=​ ​s​e​l​f​;​
m​y​B​l​o​c​k​ ​=​ ​^​{​
 ​ ​ ​ ​B​N​R​E​m​p​l​o​y​e​e​ ​*​i​n​n​e​r​S​e​l​f​ ​=​ ​w​e​a​k​S​e​l​f​;​ ​/​/​ ​a​ ​b​l​o​c​k​-​l​o​c​a​l​ ​s​t​r​o​n​g​ ​r​e​f​e​r​e​n​c​e​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​:​ ​%​@​"​,​ ​i​n​n​e​r​S​e​l​f​)​;​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​ ​I​D​:​ ​%​d​"​,​ ​i​n​n​e​r​S​e​l​f​.​e​m​p​l​o​y​e​e​I​D​)​;​
}​;​

Now there is no direct use of self, so there is no unintentional strong reference cycle. Problem solved.

In this situation, it is important to understand what the compiler is thinking to avoid the hidden strong reference cycle. However, you should never use the -> syntax to access an object’s instance variables in your code. Doing so is dangerous for reasons beyond the scope of this book. Accessors are your friends, and you should use them.

Modifying external variables

By default, variables captured by a block are constant within the block, and you cannot change their values. If you want to be able to modify an external variable within a block, you must declare the external variable using the __block keyword.

For instance, in the following code, you increment the external variable counter within the block.

_​_​b​l​o​c​k​ ​i​n​t​ ​c​o​u​n​t​e​r​ ​=​ ​0​;​
v​o​i​d​ ​(​^​c​o​u​n​t​e​r​B​l​o​c​k​)​(​)​ ​=​ ​^​{​ ​c​o​u​n​t​e​r​+​+​;​ ​}​;​
.​.​.​
c​o​u​n​t​e​r​B​l​o​c​k​(​)​;​ ​/​/​ ​I​n​c​r​e​m​e​n​t​s​ ​c​o​u​n​t​e​r​ ​t​o​ ​1​
c​o​u​n​t​e​r​B​l​o​c​k​(​)​;​ ​/​/​ ​I​n​c​r​e​m​e​n​t​s​ ​c​o​u​n​t​e​r​ ​t​o​ ​2​

Without the __block keyword, you would get a compilation error.

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

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