__block关键字

前提: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参数基本就能明白
具体细节,我有空再写~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Objective-C 1. import的用法 拷贝文件内容可以自动防止文件的内容被重复拷贝(#define宏定...
    马文涛阅读 10,712评论 3 17
  • iOS常用存储方式: XML属性列表(plist)归档; Preference(偏好设置); NSKeyedArc...
    ChenME阅读 2,224评论 0 0
  • 1.什么情况使用 weak 关键字,相比 assign 有什么不同? a.在 ARC 中,在有可能出现循环引用的时...
    坚果阅读 1,696评论 0 0
  • 1.@interface和@property的区别 在@interface中定义的变量,这能在当前的类中访问,在其...
    Natus_Vincere阅读 2,999评论 0 0
  • 在某篇文章的评论区看到一条留言,一个女读者说看到前男友在微博公布了婚讯,作了很久的心理斗争,终于鼓足勇气送上祝福。...
    蓝小巫阅读 4,138评论 1 6