preface

To ensure that external variables can be accessed from within a block, a variable capture mechanism is used.

A local variable

Auto variable (default auto)

We learned about block’s capture of the age variable in the previous code article. Auto automatic variable, destroyed when out of scope, local variables are automatically preceded by the auto keyword. Automatic variables are captured inside the block, which means that a new parameter is added inside the block to store the value of the variable. Auto only exists in local variables and is accessed by value passing. From the above explanation of the age parameter, we can also confirm that it is indeed value passing.

Static variables

Static modified variables are passed as Pointers and are also caught by the block.

Add the auto modifier to the local variable and the static modifier to the local variable. Review the source code to see the difference:

auto int a = 10;
static int b = 10;
void(^block)(void) = ^{
     NSLog(@"hello, a = %d, b = %d", a,b); // print hello, a = 10, b = 20}; a = 20; b = 20; block();Copy the code

From the command line we look at the source code:

As can be seen from the above source code, both a and B variables are captured inside the block. But A passes in a value, and B passes in an address.

The reason for this difference is that automatic variables can be destroyed, so it is possible that the automatic variable has already been destroyed at the time the block is executed. If you try to access the destroyed address, you will get bad memory access. Therefore, automatic variables must be passed by value, not by pointer. Static variables are not destroyed, so you can pass the address. Because the value of the address is passed, the address in the block will not change if the value is changed before the block is called. So the value will change.

The global variable

In the same way, we examine whether blocks capture global variables


int a = 10;
static int b = 10;
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        void(^block)(void) = ^{
            NSLog(@"hello, a = %d, b = %d", a,b); // print hello, a = 20, b = 20}; a = 20; b = 20; block(); }return 0;
}
Copy the code

The source code:

As you can see from the above code, __main_block_imp_0 does not add any variables, so the block does not need to capture global variables, which can be accessed from anywhere. Local variables need to be captured because they are accessed across functions. Global variables can be accessed anywhere, so they are not captured. So to sum it up, here’s a picture:

Summary: Local variables are captured by block, automatic variables are captured by value, static variables are captured by address. Global variables are not captured by blocks

Question: Does the block catch variables in the following code?

#import "Person.h"
@implementation Person
- (void)test
{
    void(^block)(void) = ^{
        NSLog(@"% @",self);
    };
    block();
}
- (instancetype)initWithName:(NSString *)name
{
    if (self = [super init]) {
        self.name = name;
    }
    return self;
}

@end

Copy the code