iOS 底层探索篇 ——block(下)
block底层源码
1. block底层分析
要探究block底层是什么样的一个结构,那么就定义一个block,然后xcrun 一下。
xcrun之后,打开生成的cpp文件,看到生成的main函数。
把函数的类型强转去掉之后得到下面的代码。这里看到 void(*block)(void)
等于__main_block_impl_0
函数的返回值,而block调用
等于block->FuncPtr(block)
。
搜索一下__main_block_impl_0
,那么就说明block等于这个结构体,之前的方法是这个结构体的构造函数。在main函数中定义了一个int a
,而结构体这里也有一个int a,两者之间有什么联系呢?
这里试着把block里面的a去掉,然后重新xcrun一下。这里看到结构体里的a消失了。并且构造函数里面的参数以及a(_a)消失了。a(_a)
是一个c++
的一个语法,会将传进来的参数赋值给成员变量a
。
那么也就是说:block在底层捕获了a,并形成了相对应的成员变量
。
把int 换成NSObject试一下,发现确实形成了相对应的成员变量。(这里用的NSObject,所以换到viewController文件中,重新xcrun了)。
同时注意到block的结构体这里的isa
指向的是_NSConcreteStackBlock
,这里捕获到了外界变量,为什么还是stackBlock
呢?那么是不是编译时的时候是_NSConcreteStackBlock
,到运行时的时候动态变成了mallocBlock
的呢?
还有就是这里传进来的参数fp
,赋值给了impl的FuncPtr
。fp
是 __main_block_func_0
,那么也就是说 impl.FuncPtr
= __main_block_func_0
。搜索__main_block_func_0
,发现里面是函数实现
。那么也就是说funcPtr里面存的是block的函数实现
。而之前的block->FuncPtr(block);
其实也就是调用了__main_block_func_0
。这里说明了block对fp进行了函数式保存。
这里看到int a
= __cself->a
,__cself
是传进来的参数也就是block自身
,那么__cself->a
也就是block结构体的成员变量a
。这里的int a 进行了值拷贝
。
2. __ block 的作用
在声明a的时候,添加__block
修饰。
重新xcrun
看到结构体和函数里的int a变成了__Block_byref_a_0
*a。