其实类似block和__block的实现网上随便一搜就能找到无数篇,有些分析的确实非常不错,但是或许有些人刚好就没有那个耐心去看完,有些人就算最后看完也没有理解,甚至还是没能理解其中的核心,所以这里我就根据个人的理解和网上资料的整理,简单的总结一下……
block
1.Block其实是闭包
2.Block是基于C语言的拓展
3.Block是基于指针和函数指针实现的,
4.同时他也是一种匿名函数,而且你会发现他和函数其实有很多相似的地方
5.通过打印我们可以知道他其实是一种的结构体
block的实现
Block是被设为_NSConcreteStackBlock,在栈上生成。当我们把Block作为全局变量使用时,对应生成的Block将被设为_NSConcreteGlobalBlock
Block属性
这里还有一点关于block类型的ARC属性。上文也说明了,ARC会自动帮strong类型且捕获外部变量的block进行copy,所以在定义block类型的属性时也可以使用strong,不一定使用copy。也就是以下代码:
/** 假如有栈block赋给以下两个属性 **/
// 这里因为ARC,当栈block中会捕获外部变量时,这个block会被copy进堆中
// 如果没有捕获外部变量,这个block会变为全局类型
// 不管怎么样,它都脱离了栈生命周期的约束
@property (strong, nonatomic) Block *strongBlock;
// 这里都会被copy进堆中
@property (copy, nonatomic) Block *copyBlock;
__block
Block不允许修改外部变量的值,这里所说的外部变量的值,指的是栈中指针的内存地址。__block 所起到的作用就是只要观察到该变量被 block 所持有,就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值。
总结就是:__block对象在block中是可以被修改、重新赋值的。
__block的实现
__block其实是堆栈的拷贝,
首先block修饰的变量会变成block_bref_val_0的结构体,它包含实例变量本身__forwarding(用于访问局部变量val)。
block拷贝到堆上的时候:
_val_0也会拷贝到堆上,局部变量销毁,block任然能对堆上的局部变量操作
__forwarding替换为堆上的__block变量的地址
栈上的_val_0结构体中的__forwarding指针也会指向堆上的结构体
main函数或者blcok释放的时候,只是释放了栈上的东西,所有对局部变量的操作都已经移到了对上。