Blocks:Capturing automatic variables

Capturing automatic variables

You’ve learned about Block literals and Block-type variables, and should now understand the “anonymous function” part of “anonymous functions together with auto (local) variables.”

Next, you need to learn what the “together with automatic (local) variables” part means. For Blocks, this can be rephrased as “capturing the value of automatic variables.” The next example shows how this capture is accomplished.

int main()
{
    int dmy = 256;
    int val = 10;
    const char *fmt = "val = %d\n";
    void (^blk)(void) = ^{printf(fmt, val);};

    val = 2;
    fmt = "These values were changed. val = %d\n";

    blk();

    return 0;
}

In this source code, automatic variables “fmt” and “val” are declared and then used in the Block literal. Values of the automatic variables will be captured where the Block literal is written: the values will be stored when the Block literal is executed. Because the values have already been captured, even if they are modified after the Block literal is executed, values of the variables in the Block are never affected. In this source code, the automatic variables “fmt” and “val” are modified after the Block literal. The result is:

val = 10

It doesn’t display, “These values were changed. val = 2”. It displays the result with the values at the time the Block literal is executed. When it is executed, the automatic variable “fmt” has a pointer to “val = %d\n” and the “val” has integer value 10. These values are captured at that time and then used when the Block is executed.

That sums up capturing automatic variables. There is a specifier you should learn next. It is called the __block specifier. By using it, you can modify automatic variables without capturing them. The specifier is explained in the following section.

__block specifier

When automatic variables are captured, the values are read-only in the Block. The variables can’t be modified. Next the source code tries to assign 1 to the automatic variable “val”.

int val = 0;
void (^blk)(void) = ^{val = 1;};
blk();
printf("val = %d\n", val);

In the source code, a value is assigned to the automatic variable, which is declared outside the Block literal. This causes a compile error as follows.

error: variable is not assignable (missing __block type specifier)
         void (^blk)(void) = ^{val = 1;};
                           ~~~ ^

When an automatic variable is declared outside a Block literal, you can use __block specifier to assign a value to the variable inside the Block. The following source code uses __block specifier for the automatic variable “val” so that the variable will be assignable inside the Block.

__block int val = 0;    
void (^blk)(void) = ^{val = 1;};
blk();
printf("val = %d\n", val);

The result is:

val = 1

By declaring the variable with __block specifier, you can assign values to the variable inside a Block. The __block-specified automatic variables are called “__block variables”.

Captured automatic variables

As described previously, if you assign values to a captured automatic variable, a compilation error occurs.

int val = 0;
void (^blk)(void) = ^{val = 1;};

It causes the following compilation error.

error: variable is not assignable (missing __block type specifier)        
    void (^blk)(void) = ^{val = 1;};
                      ~~~ ^

What happens when Objective-C objects are captured and a method is called to modify the object itself? Does it cause a compilation error as well?

id array = [[NSMutableArray alloc] init];
void (^blk)(void) = ^{
    id obj = [[NSObject alloc] init];
    [array addObject:obj];
};

No problem. An error will occur only if some value is assigned to the captured variable “array” itself. In this source code, the value of the captured variable is an object of the NS- MutableArray class. To rephrase it in C language terms, the value is a pointer to the instance of the struct for the NSMutableArray class object. If a value is assigned to the captured variable “array”, a compilation error will occur.

The following source code assigns a value to the captured automatic variable, so a compilation error occurs.

id array = [[NSMutableArray alloc] init];
void (^blk)(void) = ^{
    array = [[NSMutableArray alloc] init];
};


error: variable is not assignable (missing __block type specifier)
    array = [[NSMutableArray alloc] init];
  ~~~~ ^

To do that, __block specifier is needed for the automatic variable.

__block id array = [[NSMutableArray alloc] init];
void (^blk)(void) = ^{
    array = [[NSMutableArray alloc] init];
};

One more thing. When you use a C array, you have to use a pointer intentionally. Here is an example.

const char text[] = "hello";

void (^blk)(void) = ^{
     printf("%c\n", text[2]);
};

It uses an array, which has a C string literal. Nothing is assigned to the captured automatic variable. It looks to be no problem, but it causes a compilation error as follows.

error: cannot refer to declaration with an array type inside block
            printf("%c\n", text[2]);

note: declared here
        const char text[] = "hello";
       ^

That is because a C array can’t be captured by the current implementation of Blocks. You can avoid it by using a pointer as follows.

const char *text = "hello";
void (^blk)(void) = ^{
    printf("%c\n", text[2]);
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值