Objective-C Programming_ The Big Nerd Ranch Guide - Aaron Hillegass [80]
For primitive variables, this means the values are copied and stored as local variables within the block. For pointers, the block itself will keep a strong reference to any objects it references. That means that any objects referred to by the block are guaranteed to live at least as long as the block itself. (If you’ve been wondering about the difference between blocks and function pointers, it’s right here. Let’s see a function pointer do that!)
As an example, take a look at our VowelMovement program. The devowelizer block mentions two objects that were created outside of the block: newStrings (an array for storing the modified versions of strings) and string (the current string to be copied for modification). devowelizer will keep strong references to both of these objects, keeping them alive as long as the block itself exists.
Can these strong references lead to retain cycles/circular references?
You bet. The fix is the same: one of the references needs to become a weak reference. To do this, declare a __weak pointer outside the block and then reference this pointer within the block instead.
Can I change the variables that the block has copied?
By default, the variables captured by a block are constant within the block, and you cannot change their values. Object pointer variables, for example, are constant within the scope of the block. (Although you can still send the object messages that can change its contents, you cannot modify the pointer itself.)
Sometimes, however, you want to be able to modify an external variable within a block. To do this, you must declare the external variable using the __block keyword. For instance, in the following code, you increment the external variable counter.
__block int counter = 0;
void (^counterBlock)() = ^{ counter++; };
...
counterBlock(); // Increments counter to 1
counterBlock(); // Increments counter to 2
Without the __block keyword, you would get a compilation error in the block definition, indicating that the value of counter cannot be changed.
The block-based future
Blocks can be difficult to understand and to use. However, they are extremely useful and powerful in heavily event-driven applications common in Mac and iOS programming. Apple’s APIs are using blocks more and more. For instance, the ALAssetLibrary and GameKit frameworks use many block-based methods. It’s a good idea to use Apple’s block-based methods whenever they are available to become more comfortable with blocks.
Challenges
Anonymous block
The example in this chapter puts the block declaration, assignment, and usage on three separate lines of code for readability.
When you need to pass an integer into a method, such as NSNumber’s numberWithInt:, you can pass the int anonymously:
// Option 1: Totally break it down
int i;
i = 5;
NSNumber *num = [NSNumber numberWithInt:i];
// Option 2: Skip the variable declaration
NSNumber *num = [NSNumber numberWithInt:5];
Because blocks are variables, you can do this with blocks as well. In fact, this is the most common way to use blocks. You will rarely declare a block variable so that you can pass the block into methods; you’ll usually use them anonymously.
Modify the exercise in this chapter to pass the block anonymously as an argument to enumerateObjectsUsingBlock:. That is, keep the block, but get rid of the block variable.
NSNotificationCenter
In Chapter 24, you used NSNotificationCenter’s addObserver:selector:name:object: method to register to receive callbacks via your zoneChange: method. Update that exercise to use the addObserverForName:object:queue:usingBlock: method instead. Look up its details in the developer documentation.
This method takes a block as an argument and then executes the block instead of calling back to your object when the specified notification is posted. This means that your zoneChange: method will never be called. The code inside this method