Block
Block本质是一个NSBlock类型的OC对象,内部有isa指针
Block封装了函数调用以及函数调用环境
数据结构
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
| // eg: // int someVar = 20 // void (^block)(void) = ^{ // NSLog("var is %d", age); //} // block();
struct __mainblock_impl_0 {- struct __blockimpl impl; // 见下方__block_impl struct __main_block_desc_0* Desc; // 见下方__main_block_desc_0 int someVar; // 捕获的变量 // 构造函数,返回结构体对象 __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }
struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; }
static struct __main_block_desc_0 { size_t reserved; size_t Block_size; // Block的大小 } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)}; // 在这里计算了Block的大小
// 封装了block执行逻辑的函数 static void __main_block_func_0(struct __main_block_impl_0 *__cself) { // 这里是block内部的代码 }
// 执行block的代码 (已经经过简化) block->FuncPtr(block);
|
变量的捕获(capture)
- 局部变量
- auto (捕获, 值传递)
- static (捕获, 指针传递)
- 全局变量 (不捕获, 直接访问)
Block的类型
Block有3种类型,可以通过class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型
- _NSGlobalBlock_(_NSConcreteGlobalBlock) -> 数据区(.data)
- _NSStackBlock_(_NSConcreteStackBlock) -> 堆
- _NSConcreteStackBlock_(_NSConcreteMallocBlock) -> 栈
Block的copy
在ARC环境下,编译器会自动将栈上的block复制到堆上,比如如下情况
- block作为函数返回值时
- 将block赋值给__strong指针时
- block作为Cocoa API中方法名含有usingBlock的方法参数时
- block作为GCD的方法参数
对象类型的auto变量
当block内部访问了对象类型的auto变量时
- 如果block是在栈上,将不会对auto变量产生强引用
- 如果block被拷贝到堆上
- 会调用block内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,类似retain(形成强引用、弱引用)
- 如果block从堆上移除
- 会调用block内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放引用的auto变量,类似release
__block修饰符
__block可以用于解决block内部无法修改auto变量值的问题
__block不能修饰静态变量(static)、全局变量
编辑器会将__block变量包装成一个对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| __block int age = 10; ^{ NSlog(@"%d", age); }();
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __Block_byref_age_0 *age; };
struct __Block_byref_age_0 { void *__isa; __Block_byref_age_0 *__forwarding; int __flags; int __size; int age; };
|