内容简介:The ABI of Blocks consist of their layout and the runtime functions required by the compiler.
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
没有使用 v__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_literal_3 *const existingBlock; }; void __block_invoke_4(struct __block_literal_2 *_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
:
isa forwarding flags size byref_keep/byref_dispose 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
, and byref_dispose
helper 函数都应该使用 _Block_object_assign
and _Block_object_dispose
. 使用 -retain
和 -release
不会生成任何其他代码.
Blocks as Objects (作为对象)
编译器在合成属性 setter
和 getter
时将块视为对象,在以与对象相同的方式 生成 垃圾收集 strong 和 weak 信息 时将它们描述为对象,并将以与对象相同的方式 发出 强弱写入屏障分配。
__weak __block Support
OC 支持 __weak 属性的 __block 变量
, 正常情况下, 编译器使用 runtime 的 objc_assign_weak
and objc_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:
truct _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> )}; truct __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); 复制代码
以上所述就是小编给大家介绍的《Block LLVM》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
产品经理的20堂必修课
徐建极 / 人民邮电出版社 / 2013-9-1 / 59.00元
《产品经理的20堂必修课》以作者八年的产品经理工作实践为基础,通过系统的理论结合丰富的实例的方法,全面地总结了作为一名互联网产品经理所应掌握的知识。 《产品经理的20堂必修课》分为三大部分。 讲产品:深入剖析互联网产品成功的要素,分别从需求导向、简单原则、产品运营、战略布局等维度,分析如何让产品在残酷的互联网竞争中脱颖而出。 讲方法:着重分析优秀的产品团队运作的工作方法和程序,详......一起来看看 《产品经理的20堂必修课》 这本书的介绍吧!
随机密码生成器
多种字符组合密码
html转js在线工具
html转js在线工具