我们准备一个简单的block代码:
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
appDelegateClassName = NSStringFromClass([AppDelegate class]);
int age = 10;
void (^block)(int, int) = ^(int a, int b){
NSLog(@"this is a block age:%d", age);
NSLog(@"this is a block");
};
block(20,20);
}
}
将这段代码翻译成C++代码如下:
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class")));
int age = 10;
void (*block)(int, int) = ((void (*)(int, int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age));
((void (*)(__block_impl *, int, int))((__block_impl *)block)->FuncPtr)((__block_impl *)block, 20, 20);
}
return UIApplicationMain(argc, argv, __null, appDelegateClassName);
}
再将这段代码简化一下,把里面的强制类型转换可以去掉:
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class")));
int age = 10;
void (*block)(int, int) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, age));
block->FuncPtr(block, 20, 20);
}
return UIApplicationMain(argc, argv, __null, appDelegateClassName);
}
现在清晰明了,我们定义的一个block实质是一个__main_block_impl_0
函数的指针,因为我们看到是直接取__main_block_impl_0
函数的地址赋值给block的。
通过源码可以知道__main_block_impl_0
的结构是这样的:
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age;//捕获的变量
//这是一个构造方法,实际上这个__main_block_impl_0就只有上面这三个参数
__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;
}
};
我们把上面这个构造方法去掉,实际上__main_block_impl_0
就只有三个参数 struct __block_impl impl;、 struct __main_block_desc_0* Desc;和int age
,age很好理解,就是block捕获的age变量。__block_impl
的结构是这样:
struct __block_impl {
void *isa;//isa指针
int Flags;
int Reserved;
void *FuncPtr;//block封装的函数指针
};
__main_block_desc_0
的结构是这样:
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;//保存block的大小
}
里面的结构都清楚了,我们再回头看下block的定义那段代码:
void (*block)(int, int) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, age));
我们可以看到在定义block的时候__main_block_impl_0
函数接收了三个参数,其中__main_block_func_0
就是block里面执行的那段代码,这里是封装成了这样一个函数:
static void __main_block_func_0(struct __main_block_impl_0 *__cself, int a, int b) {
int age = __cself->age; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_y0_thwqbdb11zq5wklyb8jyy4km0000gn_T_main_76632f_mi_0, age);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_y0_thwqbdb11zq5wklyb8jyy4km0000gn_T_main_76632f_mi_1);
}
__main_block_desc_0_DATA
这个函数是用来获取block占用内存大小的:
__main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
当我们把这三个参数传进去之后会在__main_block_impl_0
构造方法里面赋值保存起来:
__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里面封装的那段代码的函数地址会赋值给__block_impl
的FuncPtr
,block占用内存大小信息则赋值给__main_block_impl_0
里面的Desc这里还给__block_impl
的isa指针赋值了,__block_impl
的flag默认是赋值了0。
简单说一个Block,它的底层结构就是这样:
struct __main_block_impl_0 {
void *isa;//isa指针
int Flags;
int Reserved;
void *FuncPtr;//block内部代码封装的函数指针
struct __main_block_desc_0* Desc;//block大小等信息
int age;//捕获的外部参数
};
我们直接把__block_impl
结构体拿进来,把构造函数去掉之后就是这样一个结构体了。我们发现block的第一个属性就是isa指针,所以block实际上也是一个OC对象。
网友评论