1. 什么是blcok?
Block是一个封装了函数指针和上下文的对象。
首先, Block是一个对象。
通过clang编译出来的C++文件中,我们可以看到,Block是一个包涵isa指针的结构体,而这也是blcok是一个对象的标志.
2. block的变量截取
block会截取函数中使用到的变量,将其截获,值得注意的是,这种截获是连同变量所有权修饰符一起的。也就是说,如果你使用一个__strong修饰符来修饰一个变量时,block对象会在内部生成一个__strong的实例对象来引用这个变量,这种情况就会造成常见的循环引用问题。故而我们常常使用__weak来修饰一些对象类型的局部变量,以此是block内部对变量不进行强引用而避免循环引用。
那么,在block对上下文的引用中,究竟有那些会被其直接引用呢?
首先是基本数据类型的局部变量,这种类型的变量在block的构造函数中是使用直接赋值的方式,不存在引用关系。然后是对象类型局部变量,block会默认使用相同的所有权修饰符去引用他。其他类型诸如全局变量、静态全局变量、静态局部变量则不会被block所引用。
3. block的copy操作以及堆栈中的block
上图解释了当对block进行copy时,不同位置的blcok会发生什么变化。而这种变化对于block来说也会影响到其内部所引用的实例变量。在栈中的block在其作用域结束后就被释放了,而堆中的则不会,故而如果没有属性去引用这个block的话,将会造成内存泄漏。
4. __block做了什么?
对于变量使用__block修饰后,此时的变量被转化成了一个结构体对象,其中不仅含有isa指针,而且还有一个重要的指针__forwarding指针。当__block对象没有被copy到堆中时,其forwarding指针指向他自己,而我们对被__blcok修饰过的变量做赋值操作时其实是对其__forwarding指针指向的对象做复制操作,在指针指向自己时,即为修改其自身。
当栈中的block被copy到堆中后,__block对象的__forwarding指针将指向堆中的__block对象,此时不管使用的是栈中的对象还是堆中的对象,修改的都将是堆中的block对象。
使用 __block 可以使block内部使用的变量,与外部变量(保存在栈当中的)指针保持统一。当外部发生变化时,内部指针也同样发生变化。