High Level
The ABI of Blocks consist of their layout and the runtime functions required by the compiler.
block
的 ABI (Application Binary Interface应用程序二进制接口) 由 '他们的结构布局' 和 '编译器所需的运行时函数' 组成.
block
布局结构 :
struct Block_literal_1 {
// initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
void *isa;
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;
// imported variables
};
flags:
enum {
// Set to true on blocks that have captures (and thus are not true
// global blocks) but are known not to escape for various other
// reasons. For backward compatiblity with old runtimes, whenever
// BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a
// non-escaping block returns the original block and releasing such a
// block is a no-op, which is exactly how global blocks are handled.
BLOCK_IS_NOESCAPE = (1 << 23),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
BLOCK_HAS_SIGNATURE = (1 << 30),
};
BLOCK_HAS_STRET(1 << 29)
通常被设置且总是被runtime
忽略, 它是一个过渡标记, 转换后没有被删除, 现与BLOCK_HAS_SIGNATURE(1 << 30)
配对, 表示为(3 << 30)
:
switch (flags & (3<<29)) {
case (0<<29): 10.6.ABI, no signature field available
case (1<<29): 10.6.ABI, no signature field available
case (2<<29): ABI.2010.3.16, regular calling, presence of signature
case (3<<29): ABI.2010.3.16, stret calling, presence of signature
}
block
可能发生在函数中, 其结构创建在栈局部内存中. 也可能作为全局block
变量或静态局部变量的初始化表达式存在.
基于栈结构的初始化:
-
static descriptor structure
静态描述结构的声明和初始化:-
invoke
函数指针会被设置一个以 block结构体作为第一个参数, 其余参数为 block执行复合语句时的参数的 函数. -
size
作为 block结构体 的大小 -
copy_helper
和dispose_helper
函数指针会在 block 需要时候设置
-
-
A stack (or global) Block literal data structure
栈 block 或全局 block 的声明和初始化:-
isa
被设置为_NSConcreteStackBlock
, 是由系统提供的一个没有初始化的 block 内存, 如果是静态或者文件级则会被设置为_NSConcreteGlobalBlock
. -
flags
被设置为 0, 除非 block 引用的变量需要程序级 Block_copy() 和 Block_release() 操作的 helper 函数, 这种情况下 flags 会设置为 (1 << 25).
-
example:
^ { printf("hello world\n"); }
会创建如下代码:
struct __block_literal_1 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_1 *);
struct __block_descriptor_1 *descriptor;
};
// block 执行体
void __block_invoke_1(struct __block_literal_1 *_block) {
printf("hello world\n");
}
// block 描述符结构体
static struct __block_descriptor_1 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_1 = {
0,
sizeof(struct __block_literal_1),
__block_invoke_1
};
block 初始化:
struct __block_literal_1 _block_literal = {
&_NSConcreteStackBlock,
(1<<29),
<uninitialized>,
__block_invoke_1,
&__block_descriptor_1
};
当 block 作为全局或静态局部变量时, 初始如下:
struct __block_literal_1 __block_literal_1 = {
&_NSConcreteGlobalBlock,
(1<<28)|(1<<29),
<uninitialized>,
__block_invoke_1,
&__block_descriptor_1
};
和栈 block 相比, 只是标记 flags 为全局, isa 指向修改, 这是一种优化, 可用于任何没有引入 const 或
__block变量
的 block.
Imported Variables
自动存储类变量
作为const
引入
__block 存储变量
作为一个指向一个结构体的指针
全局变量
简单引用, 不视为引入
Imported const copy variables
没有使用 __block 标记的自动变量
被作为 const
副本.
int x = 10;
void (^vv)(void) = ^{
printf("x is %d\n", x);
} // x is 10
x = 11;
vv();
会被编译为:
struct __block_literal_2 { // block
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_2 *);
struct __block_descriptor_2 *descriptor;
const int x; // const 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) };
and 初始化:
struct __block_literal_2 __block_literal_2 = {
&_NSConcreteStackBlock,
(1<<29),
<uninitialized>,
__block_invoke_2,
&__block_descriptor_2,
x // 赋值 x 的值.
};
总之,标量,结构体,联合体和函数指针通常作为 const
副本导入,不需要 helper 函数。
Imported const copy of Block reference
引入 block 的
const
副本
需要使用辅助函数copy_helper
和dispose_helper
的第一种情况是引入 block(类型)变量(existingBlock),copy_helper
传递 existingBlock 的指针和堆中的副本的指针, block 中引入的字段的 copy 操作应回调到 runtime 中确认.
block 引入 block 的 example:
void (^existingBlock)(void) = ...;
void (^vv)(void) = ^{ existingBlock(); }
vv();
struct __block_literal_3 {
...; // existing block
};
struct __block_literal_4 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_4 *);
struct __block_descriptor_4 *descriptor;
struct __block_literal_3 *const existingBlock;
};
void __block_invoke_4(struct __block_literal_4 *_block) {
_block->existingBlock->invoke(_block->existingBlock);
}
// 传入栈和堆中的 block 的指针
void __block_copy_4(struct __block_literal_4 *dst,
struct __block_literal_4 *src) {
//_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
_Block_object_assign(&dst->existingBlock,
src->existingBlock,
BLOCK_FIELD_IS_BLOCK);
}
void __block_dispose_4(struct __block_literal_4 *src) {
// was _Block_destroy
_Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
}
static struct __block_descriptor_4 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_4 *dst,
struct __block_literal_4 *src);
void (*dispose_helper)(struct __block_literal_4 *);
} __block_descriptor_4 = {
0,
sizeof(struct __block_literal_4),
__block_copy_4,
__block_dispose_4,
};
block 初始化:
struct __block_literal_4 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29),
<uninitialized>
__block_invoke_4,
& __block_descriptor_4 // 包含 copy 和 dispose
existingBlock, // 引入的 block
};
Importing __attribute__((NSObject)) variables
GCC 在结构指针上引入了
__attribute__((NSObject))
来表示“这是一个对象”, 许多低层数据结构都声明为不透明的结构指针,例如CFStringRef、CFArrayRef 等, 在 C 语言中这些仍然是真正的对象, 这是需要生成copy_helper
和dispose_helper
的第二种情况,copy_helper
生成需要调用_Block_object_assign
runtime 方法dispose_helper
调用_Block_object_dispose
方法.
example:
struct Opaque *__attribute__((NSObject)) objectPointer = ...;
...
void (^foo)(void) = ^{ CFPrint(objectPointer); };
生成以下 helper 函数:
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);
}
Imported __block marked variables
Layout of __block marked variables
编译器必须将标记为 __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 函数.
在 Objective-C 中, 对象需要 helper 函数, 而在 C++ 堆栈中, 基于栈的对象需要 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;
};
_block_byref_foo
:
- The
isa
field is set to NULL. -
forwarding
指针设置结构体地址. -
flags
如果不需要 helper 函数则设置为0. 如果是(1 << 25). -
size
初始为结构体的总大小. -
byref_keep/byref_dispose
helper 函数指针. -
marked_variable
变量自身, 设置为初始值.
Access to __block variables from within its lexical scope (__block 词法)
通过 copy_helper
操作将变量移动到堆上, 编译器必须通过结构体的 forwarding
指针重写这类变量的访问.
example:
int __block i = 10;
i = 11;
会被重写为:
struct _block_byref_i {
void *isa;
struct _block_byref_i *forwarding; // 指向自身结构体 i 的地址.
int flags; //refcount;
int size;
int captured_i; // 捕获 i 的值为 10
} i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 };
i.forwarding->captured_i = 11;
__block 标记的 block 变量, helper 的代码必需通过 runtime 使用 _Block_object_assign
和 _Block_object_dispose
生成用来制作副本.
example:
// 将 voidBlock 用 __block 标记, 会生成一个结构体
__block void (voidBlock)(void) = blockA;
voidBlock = blockB;
转换为:
struct _block_byref_voidBlock {
void *isa;
struct _block_byref_voidBlock *forwarding;
int flags; //refcount;
int size;
// block 需要 helper 函数
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)
}
and :
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;
Importing __block variables into Blocks (引入__block 标记变量)
block 复合语句体中使用 __block
变量, 必须引入变量并给出 copy_helper
和 dispose_helper
函数, 回调到运行时, 实际 copy 或者 release byref-block
是使用 _Block_object_assign
和 _Block_object_dispose
函数.
example:
int __block i = 2;
functioncall(^{ i = 10; });
转换为 :
// __block i 生成的结构体
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;
};
// block 结构体
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;
};
// block 复合语句体
void __block_invoke_5(struct __block_literal_5 *_block) {
// _block->forwarding为 byref_i 结构体, 取值改值 captured_i
_block->i_holder->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 = {( // __block i 赋值(初始化)
.isa=NULL,
.forwarding=&I,
.flags=0,
.size=sizeof(struct _block_byref_i),
.captured_i=2
)};
struct __block_literal_5 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29),
<uninitialized>,
__block_invoke_5,
&__block_descriptor_5,
&i, // i 为 byref_i 结构体.
};
Importing __attribute__((NSObject)) __block variables
__block 也可以标记
__attribute__((NSObject))
应该有byref_keep
和byref_dispose
helper 函数, 使用_Block_object_assign
和_Block_object_dispose
.
__block escapes
因为 block 引用
__block 标记的变量
可能会对他们执行Block_copy()
操作, 变量的底层存储可能移动到堆中. 在 Objective-C 中, 垃圾收集只在编译环境中进行, 使用的堆是已收集过的, 不需要进一步的操作. 否则在其作用域的所有转义或终止时编译器必须发出一个调用为__block变量
释放堆存储:
_Block_object_dispose(&_block_byref_foo, BLOCK_FIELD_IS_BYREF);
Nesting
block 嵌套 block 的情况下, 内部block 引入的任何变量都会被引入到所有封闭范围, 即使没有使用, 这包括 const 和 __block 的方式引入.
Objective C Extensions to Blocks
Importing Objects (引入对象)
objects
应以__attribute__((NSObject))
对待.
所有的copy_helper
,dispose_helper
,byref_keep
, andbyref_dispose
helper 函数都应该使用_Block_object_assign
and_Block_object_dispose
. 使用-retain
和-release
不会生成任何其他代码.
Blocks as Objects (作为对象)
编译器在合成属性
setter
和getter
时将 block 视为对象,在以与对象相同的方式 生成 垃圾收集 strong 和 weak 信息 时将它们描述为对象,并将以与对象相同的方式 发出 强弱写入屏障分配。
__weak __block Support
OC 支持
__weak 属性的 __block 变量
, 正常情况下, 编译器使用 runtime 的objc_assign_weak
andobjc_read_weak
两个 helper 函数用来支持__weak __block
变量的读写:
// runtime 接口, 用来读取block 内部的 __block / __weak 变量.
objc_read_weak(&block->byref_i->forwarding->i)
__weak
变量被存到一个_block_byref_foo
结构体中, block 提供 copy 和 dispose helper 函数, 以便结构体调用:
_Block_object_assign(&dest->_block_byref_i,
src-> _block_byref_i,
BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
and:
_Block_object_dispose(src->_block_byref_i,
BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
block_byref
结构体会区分 __block 变量
是否是 block(也可能是对象) 进行调用:
object
:
_Block_object_assign(&dest->_block_byref_i,
src->_block_byref_i,
BLOCK_FIELD_IS_WEAK |
BLOCK_FIELD_IS_OBJECT |
BLOCK_BYREF_CALLER);
block
:
_Block_object_assign(&dest->_block_byref_i,
src->_block_byref_i,
BLOCK_FIELD_IS_WEAK |
BLOCK_FIELD_IS_BLOCK |
BLOCK_BYREF_CALLER);
完整的例子:
__block __weak id obj = <initialization expression>;
functioncall(^{ [obj somemessage]; });
the block byref part:
struct _block_byref_obj {
void *isa; // uninitialized
struct _block_byref_obj *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 *);
id captured_obj;
};
void _block_byref_obj_keep(struct _block_byref_voidBlock *dst,
struct _block_byref_voidBlock *src) {
//_Block_copy_assign(&dst->captured_obj, src->captured_obj, 0);
_Block_object_assign(&dst->captured_obj, src->captured_obj,
BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
}
void _block_byref_obj_dispose(struct _block_byref_voidBlock *param) {
//_Block_destroy(param->captured_obj, 0);
_Block_object_dispose(param->captured_obj,
BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
};
block part :
// block
struct __block_literal_5 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_5 *);
struct __block_descriptor_5 *descriptor;
struct _block_byref_obj *byref_obj;
};
// block_invoke
void __block_invoke_5(struct __block_literal_5 *_block) {
// 通过 runtime 读取 block 捕获的 obj
[objc_read_weak(&_block->byref_obj->forwarding->captured_obj)
somemessage];
}
// block_copy
void __block_copy_5(struct __block_literal_5 *dst,
struct __block_literal_5 *src) {
//_Block_byref_assign_copy(&dst->byref_obj, src->byref_obj);
_Block_object_assign(&dst->byref_obj, src->byref_obj,
BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
}
// block_dispose
void __block_dispose_5(struct __block_literal_5 *src) {
//_Block_byref_release(src->byref_obj);
_Block_object_dispose(src->byref_obj,
BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
}
// block_descriptor
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
};
the compound statement part:
struct _block_byref_obj obj = {(
.forwarding=&obj,
.flags=(1<<25),
.size=sizeof(struct _block_byref_obj),
.byref_keep=_block_byref_obj_keep,
.byref_dispose=_block_byref_obj_dispose,
.captured_obj = <initialization expression>
)};
struct __block_literal_5 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29),
<uninitialized>,
__block_invoke_5,
&__block_descriptor_5,
&obj, // _block_byref_obj 指针引用 containing "captured_obj"
};
functioncall(_block_literal->invoke(&_block_literal));
C++ Support
一个 block内的 基于C++堆栈的对象, 使用
copy constructor
拷贝为 const 副本.
如果这个对象没有copy constructor
, 就会报错.
为了 block 支持Block_copy()
操作, 必须为 block 合成 copy 和 destroy helper 函数, 并且 flags 除了标记为(1 << 25)外, 还要使用(1 << 26).
copy helper
通过基于 block堆栈 适当的偏移量调用 copy constructor
创建 const 副本, 调用 destructor 的逻辑与之相似.
block 中引入 C++ 对象的例子:
{
FOO foo; // C++ obj
void (^block)(void) = ^{ printf("%d\n", foo.value()); };
}
编译结果:
struct __block_literal_10 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_10 *);
struct __block_descriptor_10 *descriptor;
const FOO foo;
};
void __block_invoke_10(struct __block_literal_10 *_block) {
printf("%d\n", _block->foo.value());
}
void __block_literal_10(struct __block_literal_10 *dst,
struct __block_literal_10 *src) {
// C++ constructor
FOO_ctor(&dst->foo, &src->foo);
}
void __block_dispose_10(struct __block_literal_10 *src) {
// C++ distructor
FOO_dtor(&src->foo);
}
static struct __block_descriptor_10 {
unsigned long int reserved;
unsigned long int Block_size;
void (*copy_helper)(struct __block_literal_10 *dst,
struct __block_literal_10 *src);
void (*dispose_helper)(struct __block_literal_10 *);
} __block_descriptor_10 = {
0,
sizeof(struct __block_literal_10),
__block_copy_10,
__block_dispose_10
};
the code :
{
FOO foo;
comp_ctor(&foo); // default constructor
struct __block_literal_10 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<26)|(1<<29),
<uninitialized>,
__block_invoke_10,
&__block_descriptor_10,
};
// block 栈中 const 版本.
comp_ctor(&_block_literal->foo, &foo);
// block 赋值
struct __block_literal_10 &block = &_block_literal;
// invoke block 调用
block->invoke(block);
// destroy stack version of const block copy 销毁栈中const 副本对象
comp_dtor(&_block_literal->foo);
// destroy original version 销毁原始对象
comp_dtor(&foo);
}
__block C++对象
和其他变量一样开始存储在block_byref
结构中的堆栈上, 这些对象(不是const对象)必须有一个常规的copy constructor
, 编译器为block_byref 结构体
合成 copy 和 destroy helper 函数,copy helper
函数会生成执行block_byref
的copy constructor
, 并设置(1 << 25)和(1 << 26)位. destroy helper 函数会对在block_byref
结构体中存储的对象执行 destructor.
例如:
__block FOO blockStorageFoo;
constructor:
FOO_ctor(& _block_byref_blockStorageFoo->blockStorageFoo);
the destructor:
FOO_dtor(& _block_byref_blockStorageFoo->blockStorageFoo);
注意, 没有使用 forwarding.
编译器将需要(为 FOO 类/结构体)生成(如果使用在 block 中)以下的copy/dispose helper:
void _block_byref_obj_keep(struct _block_byref_blockStorageFoo *dst,
struct _block_byref_blockStorageFoo *src) {
FOO_ctor(&dst->blockStorageFoo, &src->blockStorageFoo);
}
void _block_byref_obj_dispose(struct _block_byref_blockStorageFoo *src) {
FOO_dtor(&src->blockStorageFoo);
}
为了支持成员变量和函数访问, 编译器将合成一个指向该指针的 block版本 的 const 指针.
Runtime Helper Functions
runtime helper 方法描述在
/usr/local/include/Block_private.h
中, 总的来说, 如果block 引入了block 变量
,__block变量
,__attribute__((NSObject)) 变量
, 或者通过 constructor/destructor 拷贝的 C++对象
, 需要copy/dispose helper
函数. 如果函数生成则设置(1 << 26).
block 的 copy
和 dispose
函数:
copy:
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<apropos>);
dispose:
_Block_object_dispose(->target, BLOCK_FIELD_<apropos>);
apropos:
enum {
// id, NSObject, __attribute__((NSObject)), block, ...
BLOCK_FIELD_IS_OBJECT = 3,
BLOCK_FIELD_IS_BLOCK = 7, // a block variable
// the on stack structure holding the __block variable
BLOCK_FIELD_IS_BYREF = 8, // 栈结构体持有 __block 变量
BLOCK_FIELD_IS_WEAK = 16, // declared __weak
BLOCK_BYREF_CALLER = 128, // byref copy/dispose helpers called
};
block_byref
结构同样需要 对block变量
、_attribute__((NSObject))变量
或c++ 使用constructor/destructor const复制对象
使用copy/dispose helper
, 同样设置(1<<26)位, 并以相同的方式生成函数.
ObjC 下允许
__weak
属性修饰__block
, 这导致在block_byref
中调用copy/dispose helper
时需要的标记位组合BLOCK_FIELD_<apropos>
.
helper 函数的原型:
/* Certain field types require runtime assistance when being copied to the
heap. The following function is used to copy fields of types: blocks,
pointers to byref structures, and objects (including
__attribute__((NSObject)) pointers. BLOCK_FIELD_IS_WEAK is orthogonal
to the other choices which are mutually exclusive. Only in a Block
copy helper will one see BLOCK_FIELD_IS_BYREF.
* 某些字段类型在复制到堆时需要运行时帮助. 下面的函数用于复制类型的字段:
blocks、指向byref结构的指针和对象(包括_attribute__((NSObject))指针).
BLOCK_FIELD_IS_WEAK 正交于其他互斥的选项.
BLOCK_FIELD_IS_BYREF 仅仅只存在 Block copy helper 函数中.
*/
void _Block_object_assign(void *destAddr,
const void *object,
const int flags);
/* Similarly a compiler generated dispose helper needs to call back for
each field of the byref data structure. (Currently the implementation
only packs one field into the byref structure but in principle there
could be more). The same flags used in the copy helper should be
used for each call generated to this function:
* 类似地, 编译器生成 dispose helper 需要对 byref 结构体的每个字段进行回调.
(目前实现只将一个字段打包到byref结构中,但原则上可以有更多).
相同的, copy helper 中使用的 flags标志应该被该函数生成的所有调用使用.
*/
void _Block_object_dispose(const void *object, const int flags);