美文网首页
Block知识整理

Block知识整理

作者: 水水兔 | 来源:发表于2019-07-11 15:53 被阅读0次

<font color = 'gray'>2018-10-26 编辑 :yzl </font>

1. block定义

用Apple文档的话来说,A block is an anonymous inline collection of code, and sometimes also called a "closure".
关于闭包,我觉得阮一峰的一句话解释简洁明了:闭包就是能够读取其它函数内部变量的函数。
这个解释用到block来也很恰当:一个函数里定义了个block,这个block可以访问该函数的内部变量

2. Block数据结构

struct Block_descriptor_1 {
    uintptr_t reserved;
    uintptr_t size;
};

struct Block_layout {
    void *isa;
    volatile int32_t flags; // contains ref count
    int32_t reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor_1 *descriptor;
    // imported variables
};
blockStruct.png

在objc中,根据对象的定义,凡是首地址是*isa的结构体指针,都可以认为是对象(id)。这样在objc中,block实际上就算是对象。

其结构体成员如下:

  • isa,指向所属类的指针,也就是block的类型
  • flags,标志变量,在实现block的内部操作时会用到
  • Reserved,保留变量
  • FuncPtr,block执行时调用的函数指针

可以看出,它包含了isa指针(包含isa指针的皆为对象),也就是说block也是一个对象(runtime里面,对象和类都是用结构体表示)。

<font color = red> 重点理解以下话:</font>
<font color = #855e42>编译器会根据block捕获的变量,生成具体的结构体定义。block内部的代码将会提取出来,成为一个单独的C函数。创建block时,实际就是在方法中声明一个struct,根据捕获到的变量生成相应的成员变量,并且用捕获到变量的值初始化该struct的成员。而执行block时,就是调用那个单独的C函数,并把该struct指针做为函数参数传递过去。</font>

int main(int argc, char * argv[]) {
    @autoreleasepool {
        int a = 0;
          void(^block)(void) = ^{
              int b = a;
              };

                block();
                a ++;

                return 0;
              }
}

clang (clang -rewrite-objc main.m)之后


blockclang.png

自动变量val虽然被捕获进来了,但是是用 __cself->val来访问的。Block仅仅捕获了val的值,并没有捕获val的内存地址。所以在__main_block_func_0这个函数中即使我们重写这个自动变量val的值,依旧没法去改变Block外面自动变量val的值。

3. Block 类型

block中的isa指向的是该block的Class。在block runtime中,定义了6种类:

    _NSConcreteStackBlock     栈上创建的block

    _NSConcreteMallocBlock    堆上创建的block

    _NSConcreteGlobalBlock   作为全局变量的block

    _NSConcreteWeakBlockVariable

    _NSConcreteAutoBlock

    _NSConcreteFinalizingBlock

其中我们能接触到的主要是前3种,后三种用于GC不再讨论

4. __block类型的变量

默认block捕获到的变量,都是赋值给block的结构体的,相当于const不可改。为了让block能访问并修改外部变量,需要加上__block修饰词。
加了个__block,被捕获的变量会生成了一个struct(struct __Block_byref)。这个struct的首地址同样为*isa。

举个例子:
原代码:

14719DF5-2C1E-4178-B222-0C9D2C65033E.png

用clang编译结果


71A1BB78-95EF-431D-B7CD-E5E131F2D65D.png

从上面编译结果可以看出,__block修饰的局部变量a,被生成一个·__Block_byref_a_0结构体,并且拷贝一份到堆上,关系图如下:

1194012-5f5f486bab68191f.jpg

之后对a操作都是对堆中a值操作,如 (a.__forwarding->a) ++ ,在block 打印a的值,也是(a.__forwarding->a)从而达到了改变a值的目的。

5. 结束语

Block不允许修改外部变量的值,这里所说的外部变量的值,指的是栈中指针的内存地址,全局变量,全局静态变量以及静态变量之所以能修改,是因为这些变量都不是在栈上。__block 所起到的作用就是只要观察到该变量被 block所持有,就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值。

待完善,待纠正。。。。。。。。。。

参考文献

  1. [objc 中的 block](https://blog.icdd bireme.com/2013/11/27/objc-block/#more-41448)
  2. 深入研究Block捕获外部变量和__block实现原理
  3. iOS中__block 关键字的底层实现原理

相关文章

  • Block知识整理

    2018-10-26 编辑 :yzl 1. block定义 用Apple文档的话来说,A block is an...

  • iOS知识整理-Block

    Block是将函数及其执行上下文封装起来的对象 变量截获 局部变量截获 是值截获 〜局部静态变量截获 是指针截获 ...

  • Block知识小结

    这篇博客将系统整理一下Block相关的知识 首先,先思考一个问题Block能做些什么? Block内部能够读取外部...

  • # iOS基础 # block知识整理

    什么是block 在iOS 4.0之后,block横空出世,它本身封装了一段代码并将这段代码当做变量,通过bloc...

  • block 知识点整理

    block 本质 block 本质上也是一个oc对象,它内部也有一个isa指针 block是封装了函数调用以及函数...

  • Block 初见

    Block 初见 介绍 iOS block 的相关知识 目录 Block 背景知识 Block 使用方式 Bloc...

  • Block整理

    Block 概念 闭包 = 一个函数「或指向函数的指针」+ 该函数执行的外部的上下文变量「也就是自由变量」;Blo...

  • 整理Block

    用了Block那么久,一直以来没有好好整理,只知道如何使用,对有些概念也不是了解特别清楚,感觉似懂非懂的。借助网上...

  • Block整理

    Block block其实就是一个代码块,把你想要执行的代码封装在这个代码块里,等到需要的时候再去调用。那bloc...

  • block-整理中

    block-整理中

网友评论

      本文标题:Block知识整理

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