一个block主要的结构如下:
struct Block_literal_1 {
void *isa; // 初始化为 &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor_1 {
unsigned long int reserved; // NULL
unsigned long int size; // sizeof(struct Block_literal_1)
// optional helper functions
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
void (*dispose_helper)(void *src); // IFF (1<<25)
// required ABI.2010.3.16
const char *signature; // IFF (1<<30)
} *descriptor;
// 引用的变量...
};
When a Block literal expression is evaluated the stack based structure is initialized as follows:
- 声明一个static descriptor,并且按照下面方式初始化:
invoke函数指针指向一个以Block作为第一个参数、Block参数作为其余参数的函数,函数体是block的函数体。
size设置成Block literal结构体的大小
copy_helper 和 dispose_helper指针设置为Block literal需要的对应helper函数.
- 一个stack (或global) Block literal 的数据结构按照下面的方式进行创建和初始化:
- isa 设置为_NSConcreteStackBlock的地址,或者是_NSConcreteGlobalBlock的地址(如果Block是static或file level).
- flags通常设置为0,除非block截获的变量需要helper函数(Block_copy() 和 Block_release() )operations.
引入变量(Imported Variables)
auto storage class的变量会作为const copies在block中使用。__block storage class的变量作为一个指向数据结构的指针被引入使用。全局的变量仅仅作为引用,不被看作是被引入。
比如下面的代码:
int x = 10;
void (^vv)(void) = ^{ printf("x is %d\n", x); }
x = 11;
vv();
被编译成:
struct __block_literal_2 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_2 *);
struct __block_descriptor_2 *descriptor;
const int x;
};
void __block_invoke_2(struct __block_literal_2 *_block) {
printf("x is %d\n", _block->x);
}
static struct __block_descriptor_2 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_2 = { 0, sizeof(struct __block_literal_2) };;
struct __block_literal_2 __block_literal_2 = {
&_NSConcreteStackBlock,
(1<<29), ,
__block_invoke_2,
&__block_descriptor_2,
x
};
scalars、structures、unions和函数指针作为const copies引入block,不需要helper函数。
引入attribute((NSObject))变量
GCC针对结构体引入了attribute((NSObject))来表示这个结构体指针是一个对象。因为许多底层的数据结构被声明为opague structure指针,比如CGStringRef、CFArrayRef。从C转换过来时,它们其实就是对象。需要生成针对它们的copy和dispose函数。
比如下面的例子:
struct Opaque *__attribute__((NSObject)) objectPointer = ...;
...
void (^foo)(void) = ^{ CFPrint(objectPointer); };
会编译出下面的helper function:
void __block_copy_foo(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
_Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
}
void __block_dispose_foo(struct __block_literal_5 *src) {
_Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
}
引入__block变量
编译器会将__block标示的变量编译成如下结构:
struct _block_byref_foo {
void *isa;
struct Block_byref *forwarding;
int flags; //refcount;
int size;
typeof(marked_variable) marked_variable;
};
当针对一个block之行Block_copy或Block_release时,一些特定的类型变量需要helper函数。在C语言层次,只有Block类型或者_attribute((NSObject))类型会有helper函数。OC对象都需要helper函数,C++基于stack的对象需要helper函数。拥有helper函数的变量会编译成下面的形式:
struct _block_byref_foo {
void *isa;
struct _block_byref_foo *forwarding;
int flags; //refcount;
int size;
// helper functions called via Block_copy() and Block_release()
void (*byref_keep)(void *dst, void *src);
void (*byref_dispose)(void *);
typeof(marked_variable) marked_variable;
};
其初始化过程如下:
- forwarding指针指向结构体的开头
- size设置为结构题的大小
- flags设置为0,有helper函数时设置为1<<25
- helper函数初始化
- 变量设置为初始值
- isa设置为NULL
在lexical scope内访问__block变量
当执行copy_helper是,为了将变量“移动”到堆上,编译器必须将对这个变量的访问重写成间接访问结构体的forwarding指针。比如:
int __block i = 10;
i = 11;
会编译成:
struct _block_byref_i {
void *isa;
struct _block_byref_i *forwarding;
int flags; //refcount;
int size;
int captured_i;
} i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 };
i.forwarding->captured_i = 11;
如果一个Block引用的变量被标记为__block,会生成helper函数。比如:
__block void (voidBlock)(void) = blockA;
voidBlock = blockB;
会编译成:
struct _block_byref_voidBlock {
void *isa;
struct _block_byref_voidBlock *forwarding;
int flags; //refcount;
int size;
void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
void (*byref_dispose)(struct _block_byref_voidBlock *);
void (^captured_voidBlock)(void);
};
void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
//_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
_Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
}
void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
//_Block_destroy(param->captured_voidBlock, 0);
_Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
.byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
.captured_voidBlock=blockA )};
voidBlock.forwarding->captured_voidBlock = blockB;
将__block变量引入blocks中
如果一个block使用了__block变量,它必须生成copy_helper和dispose_helper。比如:
int __block i = 2;
functioncall(^{ i = 10; });
会被编译成:
struct _block_byref_i {
void *isa; // set to NULL
struct _block_byref_voidBlock *forwarding;
int flags; //refcount;
int size;
void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
void (*byref_dispose)(struct _block_byref_i *);
int captured_i;
};
struct __block_literal_5 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_5 *);
struct __block_descriptor_5 *descriptor;
struct _block_byref_i *i_holder;
};
void __block_invoke_5(struct __block_literal_5 *_block) {
_block->forwarding->captured_i = 10;
}
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
//_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
_Block_object_assign(&dst->captured_i, src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}
void __block_dispose_5(struct __block_literal_5 *src) {
//_Block_byref_release(src->captured_i);
_Block_object_dispose(src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}
static struct __block_descriptor_5 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
void (*dispose_helper)(struct __block_literal_5 *);
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };
//对应的编译代码
struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
struct __block_literal_5 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29), ,
__block_invoke_5,
&__block_descriptor_5,
2,
};