den330
den330

Reputation: 403

How does Objective-C block capture a non-object value?

int anInteger = 42;

void (^testBlock)(void) = ^{
    NSLog(@"Integer is: %i", anInteger);
};

anInteger = 84;

testBlock();

Integer is: 42

This is an example from Apple official guide.

Now, for object value, it is easy to understand, it keeps a reference to it. So later on, when it's original reference changes to point to something else, or simply gets destroyed. This reference is still there, so reference count won't be zero, and the original value is kept.

But, for the example code above, it is not an object. The block keeps a reference to it, and then the value changes to 84. I suppose that is a change to itself instead of its copy, that means the value the pointer pointing to has changed. How can it still be 42?

Upvotes: 1

Views: 1636

Answers (3)

Amin Negm-Awad
Amin Negm-Awad

Reputation: 16660

To make a long story short: Integral values are copied. (To be more precise: structs and object references are copied, too. But in the case of object references, it is a reference.)

BTW: This is the meaning of a closure. This is what closure are made for. The reason for their existence. You want exactly this behavior. Otherwise you would have to ensure, that a value is not changed while a block is running – maybe seconds or minutes later.

Upvotes: 1

rmaddy
rmaddy

Reputation: 318944

From the Blocks and Variables section of the documentation:

The following rules apply to variables used within a block:

  1. Global variables are accessible, including static variables that exist within the enclosing lexical scope.
  2. Parameters passed to the block are accessible (just like parameters to a function).
  3. Stack (non-static) variables local to the enclosing lexical scope are captured as const variables. Their values are taken at the point of the block expression within the program. In nested blocks, the value is captured from the nearest enclosing scope.
  4. Variables local to the enclosing lexical scope declared with the __block storage modifier are provided by reference and so are mutable. Any changes are reflected in the enclosing lexical scope, including any other blocks defined within the same enclosing lexical scope. These are discussed in more detail in The __block Storage Type.
  5. Local variables declared within the lexical scope of the block, which behave exactly like local variables in a function. Each invocation of the block provides a new copy of that variable. These variables can in turn be used as const or by-reference variables in blocks enclosed within the block.

Rule 3 applies to the code in your question.

Upvotes: 10

Alexander
Alexander

Reputation: 63397

Blocks introduce the necessary indirection to make sure this happens. Variables that appear to be local but which are captured by blocks are actually allocated on the heap by the compiler. Among other things, this is necessary for that variable to be able to outlive the lifetime of the function it was declared in.

Upvotes: 1

Related Questions