Block类型和捕获变量

2019-05-24  本文已影响0人  分流替躺欧阳克

Block类型

1:类型区别特征

Block是OC的对象,他也有类型,我在打印[block class]的时候可以看到有不同的block类型。

block 有三种类型,凡是访问了auto变量的便是__NSStaticBlock__类型,没有访问auto的是__NSGlobalBlock__,调用了copy的是__NSMallocBlock__。

他们的内存区域:

1:在全局区的__NSGlobalBlock__

2:在栈空间的__NSStaticBlock__

3:在堆空间的__NSMallocBlock__

这三个都继承于NSBlock,NSBlock继承于NSObect。

2:block的copy操作

在栈空间创建的block是__NSStaticBlock__,对它进行copy操作会把它变成__NSMallocBlock__类型,另外说明的是要在Objective-C Automatic Reference Counting 设置是否是ARC YES是ARC,需要调整成MRC模式才能看到类型转换。__NSMallocBlock__类型的block才能赋值给全局变量。如下

block = [^{NSLog("This block type is Malloc")} copy];

在ARC的环境下,一些情况,编译器会将block自动 copy搬到堆上去;

1:block作为返回值。

2:将block赋值给强指针__strong

3:block作为Cocoa API中方法名含有usingBlock的方法参数时。

4:block作为GCD API的方法参数时。

3:对象类型的auto变量

当我们的block对对象类型的变量捕获时,底层编译的代码__main_block_desc_0里会产生两个函数__main_block_copy_0和__main_block_dispose_0,block结构体里面也会多个成员接收被捕获的变量对象Person

在栈上的block 不会对auto类型的对象产生强引用。

如果block被拷贝到堆上,会调用内部的copy函数 ,copy函数内部会调用_Block_object_assign函数。_Block_object_assign函数会根据auto变量的修饰符(__strng,__weak, __unsafe_unretained)做出相应的操作。类似retain(强引用,弱引用)

如果block从堆上移除,会调用block内部的dispose函数。dispose函数内部会调用__Block_object_dispose函数 ,这个函数会自动释放引用的auto变量,类似release。

当block内部捕获了对象型auto变量时,block的核心结构体里会多个成员接收变量

__main_block_desc_0结构体里会多两个函数

捕获变量

变量分全局变量,和局部变量,其中局部变量分auto和static类型。

我们平常声明变量 比如:int a = 10;默认类型就是auto,离开了作用域就会销毁。

如果,在block内访问外部的变量,block会在内部声明成员接受外部的值,这叫捕获变量,auto是值捕获,在block里改变值不会改变作用域外面的值,static是指针捕获,在block内改变值会改变作用域外的值。全局变量不会被捕获,block可以直接调用。

图-01

上图代码中age_,和height_是全局变量。上面那段代码,编译后的C++代码如下:

图-02

__block 修饰符所干的事

我们在经常会在block修改外部变量,当我们修改外部的变量是static或者只是使用指针类型传递的变量时,不需要加__block,而要修改它的值就需要加__block.

__block到底做了什么,如下代码

在编译后的C++代码是:

由上面三幅图可以看出,当我们用__block修饰变量时,底层会对变量进行一个包装,把变量封在一个结构体里,如果被修饰的是对象,那么结构体里还会有copy和dispose函数,对对象进行retain和copy操作

上一篇下一篇

猜你喜欢

热点阅读