美文网首页
__block关键字

__block关键字

作者: George_Luofz | 来源:发表于2018-03-15 17:01 被阅读21次

    前提: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();
    }
    
    • block中不能修改外部变量的值?
      block中外部变量的值是被拷贝过去的,相当于值引用,并非变量原地址;
      由上方代码的输出结果可见:
    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内的地址不同,说明变量的地址没变,相当于值引用

    • 加__block关键字之后,可以修改了?
      前边加入__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关键字代码
    • 未加__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);
    }
    
    • 加入__block关键字之后,编译的核心代码如下:
    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参数基本就能明白
    具体细节,我有空再写~

    相关文章

      网友评论

          本文标题:__block关键字

          本文链接:https://www.haomeiwen.com/subject/avphqftx.html