Block内存管理1

__block修饰符所干的事

我们在经常会需要在block修改外部变量,而变量是值传递的时候,我们在block里是无法修改的。

int age = 10; 这里我们声明的变量默认是auto类型。

void (^block)(void) = ^{ age = 10;  }这是错误的,不能在block里修改外部的变量,block捕获外部变量,对于auto类型的局部变量,是值捕获,block里的a只是复制了a的值。我们可以去访问,但是不能修改

针对这种情况,我们在变量前加个__block 修饰符,__block int age = 10;这样就能达到在block里修改变量的目的了。

然而__block到底做了什么,起到了可以把外部值传递进来的对象在里面进行修改呢?如下图,写段测试代码

__block 修饰基础数据类型:

2304477-6346bb457227d6a1.png
图-01

然后利用终端clang编译器,重新编译我们这个文件成C++文件

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m -o main-arm64-arc.cpp.

在沙盒里会生成一个main-arm64-arc.cpp文件,这个文件与系统编译时,编译出来的文件是类似的,只是细节有些地方会不同。

我们可以看到 图-02 里与OC代码对应的这块,是声明的__Block_byref_age_0 对象而不是int age。然后声明block的地方,红色区域把这个变量传了进去,调用__main_block_impl_0(这个结构体便是block在C++的表现形式,block底层原理的文章有具体说明)的构造函数返回这个结构体的指针。__main_block_impl_0里如 图-03 所示,有一个__Block_byref_age_0成员,再接着看这个__Block_byref_age_0是什么东西,

2304477-f7e21d77449f91d7.png
图-02

我们的block结构体里会存着这个包装__block修饰的变量结构体,这个结构体是什么东西呢,如图-04所示。

2304477-d6524cee3e7ce4db.png
图-03

这个__Block_byref_age_0里的age便是我们在外面的变量。

2304477-71ece92041e4de1a.png
图-04

如何证明这个age便是外面的age呢,我们可以模拟这个文件的几个结构体,强转block对象,若如之前所说,被强转的block里面肯定有上图的几个属性。如下代码:

2304477-5496904aa9197f5f.png
图-05

这里最后打印的确实是同一个地址。

如果__block修饰的是对象类型的变量,还会在__main_block_desc_0里生成两个函数,这两个函数,copy在block由栈空间搬到堆空间时被调用,disoise在block被销毁时调用。

补充1:__main_block_impl_0里对__Block_byref_age_0结构体成员在ARC环境永远下是强引用,在__Block_byref_age_0结构体里,外面捕获进来的变量如果是对象才会有强弱引用之分,在MRC情况下是弱引用,MRC编译环境的情况下,在解决循环引用的问题上,可以用__block修饰符,也能解决循环引用的问题。


2304477-674c5878e307bed2.png
2304477-b495ac678bdded09.png

补充2:在block代码块封装的函数里,访问这个外面捕获的__block所修饰的变量是通过age->__forwarding->age这样的形式,其中第一个age 是__Block_byref_age_0结构体,__forwarding是指向__Block_byref_age_0结构体自己的指针,再通过指向自己的指针访问真正age。为什么不直接通过结构体age->age呢,因为,在函数里,block默认是在栈的,但是ARC环境下,系统会默认对blockcopy搬到堆上,而block结构体里的__block变量还是在栈上,这样在堆上的__Block_byref_age_0结构访问栈上的__block变量就会存在危险,所以弄了个__forwarding指针,他是指向堆上的__Block_byref_age_0结构体,这样的话,不管这个__Block_byref_age_0是在堆上还是在栈上的,里面的__forwarding指针都是指向堆里的__Block_byref_age_0结构体自己。


2304477-7f03bb5347618f0f.png

转载于:https://www.jianshu.com/p/32ff9558bd7a

猜你喜欢

转载自blog.csdn.net/weixin_34259159/article/details/91166268