一 : 基本结构
写一个简单的block
int age = 20;
void (^block)(int, int) = ^(int a , int b){
NSLog(@"this is a block! -- %d", age);
NSLog(@"this is a block!");
NSLog(@"this is a block!");
NSLog(@"this is a block!");
};
block本质其实是一个OC
对象,其源码结构如下,
有一个isa
指针,可以看出来block是一OC对象,其中
main_block_desc这个结构体是对block的描述,reserved
是扩展保留,Block_size
是block所占用的大小
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
其中block的impl结构体的结构体保存了block的函数地址
二 : block执行过程源码分析
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
// 第一步 : 定义block变量
void (*block)(void) = &__main_block_impl_0(
__main_block_func_0,
&__main_block_desc_0_DATA
);
//第二步 执行block内部的代码
block->FuncPtr(block);
}
return 0;
}
第一步 : 就是block的一个初始化,使用c++语法,来进行构造函数初始化.最终就是block指向了一个结构体对象,两个参数分别是,函数的地址
,和block的信息
第一个参数函数地址最终保存在,block所指向结构体的impl->FuncPtr中.
第二个参数desc保存在block所指向Desc
第二步取出block所指向结构体中的impl中的FuncPtr 函数地址,调用函数.
三 : 变量捕获
-
auto捕获
auto:自动变量,离开作用域就销毁
auto int age = 10;
void (^block)(void) = ^{
// age的值捕获进来(capture)
NSLog(@"age is %d,", age);
};
图示
age
值传递到结构体变量中
-
static
static 修饰的变量,代码块过掉后不会销毁.
auto:自动变量,离开作用域就销毁
auto int age = 10;
static int height = 10;
void (^block)(void) = ^{
// age的值捕获进来(capture)
NSLog(@"age is %d, height is %d", age, height);
};
图例
height
地址传递
在block结构中height指针接受传过来的&height地址
执行的时候取出height指针所指向的值
-
全局变量
直接访问全局变量,不会捕获到block内部.