研究下block的具体实现,网上已经有过了,自己重新做下,也算是加深理解。
int main(int argc, const char * argv[]) {
@autoreleasepool {
__block int age = 10;
NSString *name = @"张三";
void (^block)() = ^{
int a = 10;
int b = 20;
int c ;
c = a + b;
NSLog(@"name %@",name);
NSLog(@"age %d",age);
};
age = 30;
block();//10
}
终端中切换到项目的.m文件路径,执行 clang -rewrite-objc main.m ,会得到一个对应的main.cpp文件,文件蛮大,3M多,直接到文件的最后,会看到这样的代码
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
NSString *name;
int age;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_name, int _age, int flags=0) : name(_name), age(_age) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSString *name = __cself->name; // bound by copy
int age = __cself->age; // bound by copy
int a = 10;
int b = 20;
int c ;
c = a + b;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_1ce142_mi_1,name);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_1ce142_mi_2,age);
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->name, (void*)src->name, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->name, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
}
__main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
int age = 10;
NSString *name = (NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_1ce142_mi_0;
void (*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, name, age, 570425344));
age = 30;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); //block的执行
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
其中 __block_impl 是一个block的内部结构,定义如下:
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
每个block会生成对应的结构体__main_block_impl_0 ,其中有个构造函数如下,
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_name, int _age, int flags=0) : name(_name), age(_age)
block内部访问的外部变量在这里都是值类型,看到这里应该很明白了吧!这也是为什么在block体里不能对外部变量进行修改。
如果要修改,需要加上__block,__block int age = 10,在看
struct __Block_byref_age_0 {
void *__isa;
__Block_byref_age_0 *__forwarding;
int __flags;
int __size;
int age;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
NSString *name;
__Block_byref_age_0 *age; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_name, __Block_byref_age_0 *_age, int flags=0) : name(_name), age(_age->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_age_0 *age = __cself->age; // bound by ref
NSString *name = __cself->name; // bound by copy
int a = 10;
int b = 20;
int c ;
c = a + b;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_f23869_mi_1,name);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_f23869_mi_2,(age->__forwarding->age));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->name, (void*)src->name, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->age, (void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->name, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
__attribute__((__blocks__(byref))) __Block_byref_age_0 age = {(void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0), 10};
NSString *name = (NSString *)&__NSConstantStringImpl__var_folders_9p_zm9fm86j06j4ng_47_8jbbd40000gn_T_main_f23869_mi_0;
void (*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, name, (__Block_byref_age_0 *)&age, 570425344));
(age.__forwarding->age) = 30;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
在这里可以看到,对加了block的外部变量会生成其对应的__Block_byref_age_0,传递的参数也变成了地址(__Block_byref_age_0 *)&age,变成了引用类型, 这样当外部变量被修改后,block中也被修改。