Home > Articles > Home & Office Computing > Mac OS X

  • Print
  • + Share This
This chapter is from the book

Blocks as Objects

Interestingly enough, blocks are also objects and can be stored in collections. Blocks start out life on the call stack, making them the only stack-based Objective-C objects. The block's executable code does not actually live on the stack, but all of the data the block uses, such as local variables and captured variables, lives there.

Because these blocks live on the stack, you need to make a copy of the block into the heap if it is to live beyond the current scope. When you copy a block, any captured variables are copied into the heap as well. Figure 3.1 shows the block data on the stack for this block:

int stride = 10;

__block int summation = 0;

BoringBlock blockPtr = ^{
    summation += stride;
};
Figure 3.1

Figure 3.1 Block storage starts on the stack

Because summation is __block-scoped, the code inside and outside of the block refers to the same location in memory. stride, on the other hand, is a simple const-captured variable. Its value, at the time the block is defined, is duplicated and placed in another location in memory, so any changes made to stride will not corrupt the value that has been captured.

You can make a copy of a block using the -copy method, or with the Block_copy() function:

void *Block_copy (const void *block);

You can -release the copied block or use Block_release():

void Block_release (const void *block);

After the copy, memory looks like Figure 3.2. The captured values for summation and the captured stride have been moved to the heap, and a pointer has been put into place for summation so that the value can be found in the heap. This means that the address of a __block-scoped variable can change, so do not rely on it being constant.

Figure 3.2

Figure 3.2 Copies get moved to the heap

The first copy of a block can be expensive because it requires dynamic allocation. Subsequent copies of the block just turn into retains, and so are fast.

In general, -copy and Block_copy() are interchangeable, except when you are running under garbage collection. If you use -copy, you need to keep a strong reference to the block to prevent it from getting collected. Block_copy under GC behaves more like CFRetain, preventing the block from being collected even if there are no strong references to it.

Sending -retain to a block is a no-op until the block has been copied.

  • + Share This
  • 🔖 Save To Your Account