为什么不加__block不能修改变量值
普通变量,数值型或对象型,没有加__block时,Block捕获的是变量,不是变量的地址,因为在函数里对变量做修改不起任何作用,所以编译器层面禁止对捕获的变量进行修改。如果捕获的是变量的地址的话,就可以修改,例如:
static int num = 10;
bbk blk = ^{
num++;
};
NSLog(@"%d", num);
blk();
NSLog(@"%d", num);
输出结果:
10
11
编译成C++,看看对静态变量num做了什么:
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int *num;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_num, int flags=0) : num(_num) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
可以看到Block捕获的是静态变量的地址"int *num",所以可以根据这个指针对静态变量做修改。
为什么加了__block就能修改变量值
使用了__block,可以修改变量值,根本原因还是因为获取到了变量的地址,看一下这段代码:
int main(int argc, const char * argv[])
{
__block int a = 100;
Blk blk_t;
{
blk_t = ^(id obj){
a = 200;
};
}
blk_t(@"Hello");
return 0;
}
编译成C++看一下我们的“a=200”究竟做了什么,
static void __main_block_func_0(struct __main_block_impl_0 *__cself, id obj) {
__Block_byref_a_0 *a = __cself->a; // bound by ref
(a->__forwarding->a) = 200;
}
__forwarding指针是一个指向自己__block实例的指针(当在栈上时),又通过__forwarding指针取到了变量a的地址进行赋值,所以最终是拿到了变量的地址,所以可以对变量进行修改。