__block关键字

2018-03-15  本文已影响21人  George_Luofz

前提:Objective-C规定,在block中不能修改外部变量的值,若想修改则需在变量前边加__block关键字修饰
理解:

- (void)_testBlock{
     int a = 0;
    NSLog(@"block before:%p",&a);
    void (^func)(void) = ^{
        NSLog(@"block in:%p",&a);
    };
    NSLog(@"block after:%p",&a);
    func();
}
2018-03-15 16:20:44.982696+0800 iOSLearnigDemo[18642:1907706] block before:0x7ffeef0df60c
2018-03-15 16:20:44.983465+0800 iOSLearnigDemo[18642:1907706] block after:0x7ffeef0df60c
2018-03-15 16:20:44.983591+0800 iOSLearnigDemo[18642:1907706] block in:0x600000446e00

block before和block after的地址一致,和block内的地址不同,说明变量的地址没变,相当于值引用

2018-03-15 16:38:32.129721+0800 iOSLearnigDemo[18779:1930598] block before:0x7ffee4897608
2018-03-15 16:38:32.129958+0800 iOSLearnigDemo[18779:1930598] block after:0x600000238d78
2018-03-15 16:38:32.130968+0800 iOSLearnigDemo[18779:1930598] block in:0x600000238d78

block in和block after的地址是一致的,说明变量的地址变化,相当于地址引用
我们可以更进一步,利用clang 生成runtime编译后的源文件,加深理解


2. 加深理解

方式:利用clang -rewrite-objc 生成编译后的代码,用源码解读
编译完成的代码如下图所示:


编译完成的代码对比,左侧为加了__block关键字代码
void test_block(){
    int a = 0;
    printf("block before:%p",&a);
    void (*func)(void) = ((void (*)())&__test_block_block_impl_0((void *)__test_block_block_func_0, &__test_block_block_desc_0_DATA, a)); //注意此处传递给__test_block_block_impl_0函数的最后一个参数为a,所以是值传递
    printf("block after:%p",&a);
    ((void (*)(__block_impl *))((__block_impl *)func)->FuncPtr)((__block_impl *)func);
}
void test_block(){
    __attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 0};
    printf("block before:%p",&(a.__forwarding->a));
    void (*func)(void) = ((void (*)())&__test_block_block_impl_0((void *)__test_block_block_func_0, &__test_block_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
    printf("block after:%p",&(a.__forwarding->a));
    ((void (*)(__block_impl *))((__block_impl *)func)->FuncPtr)((__block_impl *)func);
}

通过查看生成的_test_block_block_impl_0函数中a参数基本就能明白
具体细节,我有空再写~

上一篇下一篇

猜你喜欢

热点阅读