void nc_test() {
void (^block1)(NSString *) = ^(NSString *str_a){
NSLog(@"----%@",str_a);
};
block1(@"abc");
int (^block2)(int) = ^(int a){
return a*2;
};
int b = block2(123);
}
用clang -rewrite-objc main.m转化上面代码
void nc_test() {
void (*block1)(NSString *) = ((void (*)(NSString *))&__nc_test_block_impl_0((void *)__nc_test_block_func_0, &__nc_test_block_desc_0_DATA));
((void (*)(__block_impl *, NSString *))((__block_impl *)block1)->FuncPtr)((__block_impl *)block1, (NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_2);
int (*block2)(int) = ((int (*)(int))&__nc_test_block_impl_1((void *)__nc_test_block_func_1, &__nc_test_block_desc_1_DATA));
int b = ((int (*)(__block_impl *, int))((__block_impl *)block2)->FuncPtr)((__block_impl *)block2, 123);
}
先关注下block1
查看与block1相关的几个结构:
struct __nc_test_block_impl_0 {
struct __block_impl impl;
struct __nc_test_block_desc_0* Desc;
__nc_test_block_impl_0(void *fp, struct __nc_test_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __nc_test_block_func_0(struct __nc_test_block_impl_0 *__cself, NSString *str_a) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_1,str_a);
}
static struct __nc_test_block_desc_0 {
size_t reserved;
size_t Block_size;
} __nc_test_block_desc_0_DATA = { 0, sizeof(struct __nc_test_block_impl_0)};
回到block1的初始化:
void (*block1)(NSString *) = ((void (*)(NSString *))&__nc_test_block_impl_0((void *)__nc_test_block_func_0, &__nc_test_block_desc_0_DATA));
可以看到是通过__nc_test_block_impl_0() 函数生成了一个对象再强转为(void (*)(NSString *))类型然后赋值给block1。
查看__nc_test_block_impl_0()
struct __nc_test_block_impl_0 {
struct __block_impl impl;
struct __nc_test_block_desc_0* Desc;
__nc_test_block_impl_0(void *fp, struct __nc_test_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
__nc_test_block_impl_0()是__nc_test_block_impl_0的构建函数,调用时需要传入两个必传参数(void *fp, struct __nc_test_block_desc_0 *desc)
__nc_test_block_impl_0结构体下包含两个子结构,分别为__block_impl、__nc_test_block_desc_0类型
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
isa指针指向&_NSConcreteStackBlock,代表block的类型
FuncPtr指向的是block中内容的实现地址,调用block时真正调用的方法地址,__nc_test_block_impl_0结构体构建时第一个参数void *fp,就是赋值给FuncPtr的。
static struct __nc_test_block_desc_0 {
size_t reserved;
size_t Block_size;
} __nc_test_block_desc_0_DATA = { 0, sizeof(struct __nc_test_block_impl_0)};
__nc_test_block_desc_0主要存储了block的大小,此处在编译时就构建了一个__nc_test_block_desc_0类型的对象__nc_test_block_desc_0_DATA,
也就是block1生成时调用__nc_test_block_impl_0()时传入的两个参数之一(&__nc_test_block_desc_0_DATA),另一个参数是(void *)类型的__nc_test_block_func_0
static void __nc_test_block_func_0(struct __nc_test_block_impl_0 *__cself, NSString *str_a) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_1,str_a);
}
所以block1的初始化就是通过__nc_test_block_impl_0结构体的构建函数,生成一个__nc_test_block_impl_0的对象。
再看block1的调用:
((void (*)(__block_impl *, NSString *))((__block_impl *)block1)->FuncPtr)((__block_impl *)block1, (NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_2);
首先关于后面一长串( (NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_2),由于调用block时传入的参数是@"abc",为常量字符串,那一串则为常量字符串的存储地址。
然后去掉大量的类型转换:
((block1)->FuncPtr)(block1,&@"abc" );
也就是对block1结构体下的FuncPtr指向的函数的直接调用。也就是直接调用了初始化block1时传入的第一个参数__nc_test_block_func_0
static void __nc_test_block_func_0(struct __nc_test_block_impl_0 *__cself, NSString *str_a) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_1,str_a);
}
关于长长的那两串都是代表代码中出现的常量字符串("abc"、"----%@"):
static __NSConstantStringImpl __NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_1 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"----%@",6};
static __NSConstantStringImpl __NSConstantStringImpl__var_folders_s__2lbjj8zs1md0wqmlr3w4zndr0000gn_T_main_76bab1_mi_2 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"abc",3};