#iOS Block 概要
##1.Block 的种类
block 常见的类型有三种: __NSGlobalBlock__(全局), __NSStackBlock__(栈), __NSMallocBlock(堆)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| int main(int argc, const char *argv[]){ @autorelease{ int i = 10; ^{i;}; void (^block) = ^{i;}; __weak void (^weakBlock) = ^{i;}; void (^stackBlock) = ^{}; } }
|
综上所述:我们可以得到如下的结论:ARC 下
1.block 没有捕获外部变量,或者用到全局变量、静态变量,则为 __NSGlobalBlock__
2.block 用到自动变量且用正常变量来接受这个 block,则是 MallocBlock
3.block 用到自动变量或者用 weak 变量来接受 block,则是 StackBlock
备注:
1.block 用到自动变量初创之时都是 StackBlock 类型,在 ARC 环境下赋值给正常变量时,系统会将 block 拷贝到堆上,StackBlock 变成了 MallocBlock
2.在 MRC 下,赋值给正常变量时,系统不会自动的将 block 拷贝到堆上。
###2.Block 内外关系
1 2 3 4 5 6
| static int a; - (void)test{ ^{ a; } }
|
1 2 3 4 5 6
| - (void)test{ static int a; ^{ a = 10; } }
|
1 2 3 4 5 6
| - (void)test{ int a; ^{ a; } }
|
1 2 3 4 5 6
| - (void)test{ __block int a; ^{ a = 10; } }
|
综上所述:__block 修饰的基础类型和对象类型都会构造__Block_byref结构体再传递。
构造__Block_byref结构体在传递的方式会很复杂。
###3.梳理
在 ARC 环境下,
__NSGlobalBlock__ 几乎不出现,使用起来没什么需要注意。
__NSStackBlock__ 几乎不出现, 但他是 __NSMallocBlock__ 的前身。
__NSMallocBlock__ 比较重要
看得懂编译是一切的前提
##1.看懂编译
编译选项:clang --rewrite-objc
A.不带参数
1 2 3 4 5 6
| int main(int argc, const char *argv[]){ @autorelease{ ^{} } return 0; }
|
编译结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| struct __block_impl{ void *isa; int Flags; int Reverse; void *FuncPtr; };
struct __main_block_impl_0{ struct __block_impl impl; struct __main_block_desc_0 *Desc; __main_block_desc_0(void *fp, struct __main_block_desc_0 *desc, int flags = 0){ impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } };
static void __main_block_func_0(struct _main_block_impl_0 *__cself){}
static struct _main_block_func_0{ size_t reserved; size_t Block_size; }__main_block_desc_0_DATA = {0, sizeof(struct __main_block_impl_0);}
int main(int argc, const char* argv[]){ void(*test)()=( (void (*))&__main_block_impl_0( (void *)__main_block_func_9, &__main_block_desc_0_DATA) ); ); ((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr((__block_impl *)test); return 0; }
|
__main_block_impl_0 就是 block 的一个 C++的实现,0 表示第几个block,其实就是一个结构体。
__block_impl 结构体中
isa指向所属类,就是 block 的类型。
flags,标志变量,在 block 内部操作中会用到。
Reserved,是保留变量。
FuncPtr,block 执行时调用的函数指针,它包含了 isa 指针,其实 block 也是一个对象。
__main_block_desc_0 结构体中
Reserved,为保留字段
Block_size 为 block 的大小,也就是sizeof(struct __main_block_impl_0)
在上面的代码中,定义__main_block_desc_0结构体时,同时创建了__main_block_desc_0_DATA,并给它赋值,以供main函数中对__main_block_0进行初始化。
__main_block_impl_0 的isa指向了__NSConcreteStackBlock
- 从
main函数中看,__main_block_impl_0的FuncPtr指向了函数__main_block_func_0
__main_block_impl_0的Desc也指向了定义的__main_block_desc_0时就创建的__main_block_desc_0_DATA,其中记录了 block 结构体大小等信息。
##2.Block 实际结构
在Block_private.h 中定义了对 block 的相关结构体的真实定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| struct Block_descriptor{ unsigned long int reserved; unsigned long int size; void (*copy)(void *dst, void *src); void (*dispose)(void *) }
struct Block_layout{ void *isa; int flags; int reserved; void (* invoke)(void *,...); struct Block_descriptor *descriptor; }
|
invoke ,相当于上文中的 FuncPtr, block 执行时调用的函数指针,block 定义时内部的执行代码都在这个函数中。
Block_descriptor,block 的详细描述
copy/dispose,辅助拷贝/销毁函数,处理 block 范围外的变量时使用。
结论:
block 就是一个里面存储了指向函数体中包含定义 block 时代码块的函数指针,以及block 外部上下文等信息的结构体。
B. 基础类型
1 2 3 4 5 6 7 8
| int main(int argc, const char *argv[]){ int any = 1; void (^test)() = ^{ NSLog(@"%d", any); }; test(); return 0; }
|
编译结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; int any; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _any, int flags=0) : any(_any) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself){ int any = __cself->any;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_a_f8f541_mi_0, any); }
static struct __main_block_desc_0 { size_t reserved; size_t Block_size; } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main (int argc, const char *argv[]){ int any = 1; void (*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, any)); ((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test); return 0; }
|
###C. 对象类型
1 2 3 4 5 6 7 8
| int main(int argc, const char *argv[]){ NSString *any = [NSString stringWithFormat:@"1"]; void (^test)() = ^{ NSLog(@"%@", any); }; test(); return 0; }
|
编译结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; NSString *any; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSString *_any, int flags=0) : any(_any) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { NSString *any = __cself->any;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_b_ca6e15_mi_2, any); }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->any, (void*)src->any, 3);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->any, 3);}
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[]){ NSString *any = ((NSString *(*)(id, SEL, NSString *, ...))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithFormat:"), (NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_b_ca6e15_mi_0, (NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_b_ca6e15_mi_1); void (*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, any, 570425344)); ((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test); return 0; }
|
###D.__block 修饰基础类型
1 2 3 4 5 6 7 8
| int main(int argc, const char * argv[]) { __block int any = 1; void (^test)() = ^ { NSLog(@"%d",any); }; test(); return 0; }
|
编译结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
struct __Block_byref_any_0 { void *__isa; __Block_byref_any_0 *__forwarding; int __flags; int __size; int any; };
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __Block_byref_any_0 *any; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_any_0 *_any, int flags=0) : any(_any->__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_any_0 *any = __cself->any;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_c_88a22a_mi_0, (any->__forwarding->any)); } static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->any, (void*)src->any, 8);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->any, 8);}
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[]){ __attribute__((__blocks__(byref))) __Block_byref_any_0 any = {(void*)0,(__Block_byref_any_0 *)&any, 0, sizeof(__Block_byref_any_0), 1}; void(*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_any_0 *)&any, 570425344)); ((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test); return 0; }
|
###E. __block修饰对象类型
1 2 3 4 5 6 7 8
| int main(int argc, const char * argv[]) { __block NSString * any = [NSString stringWithFormat:@"1"]; void (^test)() = ^ { NSLog(@"%@",any); }; test(); return 0; }
|
编译结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
static void __Block_byref_id_object_copy_131(void *dst, void *src) { _Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131); } static void __Block_byref_id_object_dispose_131(void *src) { _Block_object_dispose(*(void * *) ((char*)src + 40), 131); }
struct __Block_byref_any_0 { void *__isa; __Block_byref_any_0 *__forwarding; int __flags; int __size; void (*__Block_byref_id_object_copy)(void*, void*); void (*__Block_byref_id_object_dispose)(void*); NSString *any; };
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __Block_byref_any_0 *any; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_any_0 *_any, int flags=0) : any(_any->__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_any_0 *any = __cself->any;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_d_a788e6_mi_1, (any->__forwarding->any)); } static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->any, (void*)src->any, 8);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->any, 8);}
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[]){ __attribute__((__blocks__(byref))) __Block_byref_any_0 any = {(void*)0,(__Block_byref_any_0 *)&any, 33554432, sizeof(__Block_byref_any_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((NSString *(*)(id, SEL, NSString *, ...))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithFormat:"), (NSString *)&__NSConstantStringImpl__var_folders_n6__72n032j2fn1zsdjjvn88vrc0000gn_T_d_a788e6_mi_0)}; void (*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_any_0 *)&any, 570425344)); ((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test); return 0; }
|
##3. 结果分析
###3.1
__main_block_func_0 为 block 具体实现函数
__main_block_desc_0 为 block 大小描述 + 拷贝函数 + 销毁函数
__main_block_impl_0 block 的一切都封装在内,包括前两个函数 + 捕获的参数。该结构体就是 block 在内存里的真实存在。
- block 的调用
((void (*)(__block_impl *)) ((__block_impl *)test) -> FuncPtr)((__block_impl *)test);
###3.2 以 A 为例 block 的调用
1 2
| void (*test)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0,&__main_block_desc_0_DATA)); ((void (*)(__block_impl *))((__block_impl *)test)->FuncPtr)((__block_impl *)test);
|
- 调用
__main_block_impl_0结构体的构造函数,生成__main_block_impl_0结构体的实例,获取实例地址,将这个地址转成函数地址。
(void (*)(__block_impl *))读取地址,强转成函数
((__block_impl *)test)之类对象转换成父类,这个地方 test 指针真正的指向对象__main_block_impl_0,是一个子类对象,但是__main_block_impl_0包含了__block_impl结构体,所以读取子类对象的父类对象大小,就能取到了父类对象
###3.3 对象类型编译结果
- 拷贝
__main_block_impl_0 -> __Block_byref_any
1 2 3
| static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) { _Block_object_assign((void*)&dst->any, (void*)src->any, 3); }
|
- 销毁
__main_block_impl_0 -> __Block_byref_any
1 2 3
| static void __main_block_dispose_0(struct __main_block_impl_0*src) { _Block_object_dispose((void*)src->any, 3); }
|
###3.4 __block修饰编译结果有的