为什么 Apple 设计 __block 用于在块中写入自动变量?

Why did Apple design __block for write auto var in block?

我们可以在块中读取自动变量:

int aVar = 1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NSLog(@"theVar==%d", aVar);
});

但是写不出来:

int aVar = 1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    aVar = 2;
    NSLog(@"theVar==%d", aVar);
});

Xcode 显示:Variable is not assignable (missing __block type specifier).

我知道当没有 __block 时,auto var 作为副本传递给块,所以它是 readonly.And,其地址 __block 传递给块。

但是我不明白为什么Apple一定要这样设计?只复制地址到block不行吗?如果没有__block的block中的auto var是可写的,有没有潜在的问题?

它不像"with __block its address pass to block"那么简单,因为捕获变量的块可以比它创建的作用域更长,并且自动存储持续时间的局部变量会在作用域结束时失效,所以仅仅捕获它的地址是行不通的。

__block声明的变量实际上在幕后涉及一个隐藏的结构,如果需要,它可以"moved"从堆栈到堆,这样它就可以比创建它的范围更长久,并且编译器在幕后生成了额外的隐藏字段,以允许访问变量的人找出当时变量(堆栈或堆)的真实位置。此外,块需要管理堆上变量副本的内存。因此,与变量本身相比,定义一个 __block 变量需要额外的存储空间,而访问一个 __block 变量需要更多的间接级别和涉及的块的更多内存管理逻辑。这种额外的并发症只应在需要时使用;因此,块捕获的变量默认情况下不是 __block