__block的作用和功能
__block的作用和功能
余成海 发表于2年前
__block的作用和功能
  • 发表于 2年前
  • 阅读 56
  • 收藏 0
  • 点赞 0
  • 评论 0

移动开发云端新模式探索实践 >>>   

哈,好久没写博客了,oschina的编辑器变漂亮啦!!!!!

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

先看代码,代码这么写的话会编译失败,提示错误:

原因在于,栈上的局部变量无法在block中编辑,block只做了只读拷贝,解决的办法当然是__block修饰啦,但是__block到底有什么作用,编译器遇到__block做了什么处理,这也是面试中常问的问题。

插个问题,考下大家,看看下面的代码输出的结果是什么.大家可以试下

int val = 0;
void (^blkk)(void) =  ^{
    NSLog(@"~~~~~~~%d", val);
};
val++;
blkk();

----------------------------凌乱分割线--------------------------------

上面的结果当然是0,因为在val++之前,block已经对val做了只读拷贝,所以后来修改val和block中的val无关了,再看下下面的代码

__block int val = 0;
void (^blkk)(void) =  ^{
    NSLog(@"~~~~~~~%d", val);
};
val++;
blkk();

结果就变成1了,所以可以看出__block的作用,__block修饰的变量在block中使用时,block不会对变量只读拷贝操作。

简单说,__block说明符类似static、auto、register一样,作用是改变变量的存储区域,它会使得修饰的变量结构化到block的自动变量中去,解释下这句话,就是说val会被存储到block结构中去。看看编译结果就很清楚了

__block int val = 0;
void ^(blk)(void) = ^(val = 1);

上面这段代码通过编译器编译后出来的结果是这样的:

struct __Block_byref_val_0 {
    void *__isa;
    __Block_byref_val_0 *__forwarding;
    int __flags;
    int __size;
    int val;
};

struct __main_block_impl_0 {
    struct __block_impl  impl;
    struct __main_block_desc_0 *Desc;
    __Block_byref_val_0 *val;

    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_val_0 *_val, int flags=0) : val(_val->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
}

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    __Block_byref_val_0 *val = __cself->val;
    (val->__forwarding->val) == 1;
}

........

int main()
{
    __Block_byref_val_0 val = {
        0,
        &val,
        0,
        sizeof(__Blcok_byref_val_0),
        0
    };

    blk = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, &val, 0x2200000);

    return 0;
}

c的代码也是比较好看懂的,可以看到,int val 变成一个结构体了__Block_byref_val_0,在block的结构体中还包含了val。

 

当然大家会想到一个问题,如果有多个block会出现什么情况,同时用到val。会不会出现两个block中的val不一样呢,我们看下代码

__block int val = 0;
void (^blk0)(void) = ^{val = 1};
void (^blk1)(void) = ^{val = 2};

看下转换后的代码:

__Block_byref_val_0 val = {0, 
&val,
0,
sizeof(__block_byref_val_0, 
0)
};

blk0 = &__main_block_impl_0(__main_block,func_0, &__main_block_desc_0_DATA, &val, 0x22000000);
blk1 = &__main_block_impl_1(__main_block,func_0, &__main_block_desc_0_DATA, &val, 0x22000000);

可以看到block赋值了val结构的地址,所以两个block,拥有的是同一块val的数据。这也是编译器把val的结构体定义单独提出来,而不是放到block结构中定义的原因

标签: ios block __block
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 61
博文 56
码字总数 29577
×
余成海
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: