官方連接html
The ABI of Blocks consist of their layout and the runtime functions required by the compiler.c++
block
的 ABI (Application Binary Interface應用程序二進制接口) 由 '他們的結構佈局' 和 '編譯器所需的運行時函數' 組成.express
block
佈局結構 :api
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:ui
^ { printf("hello world\n"); }
複製代碼
會建立以下代碼:this
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.
自動存儲類變量
做爲const
引入,__block 存儲變量
做爲一個指向一個結構體的指針, 全局變量簡單引用, 不視爲引入.
沒有使用 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 函數。
引入 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
};
複製代碼
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);
}
複製代碼
編譯器必須將標記爲 __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
field is set to NULL.forwarding
指針設置結構體地址.flags
若是不須要 helper 函數則設置爲0. 若是是(1 << 25).size
初始爲結構體的總大小.byref_keep/byref_dispose
helper 函數指針.marked_variable
變量自身, 設置爲初始值.經過 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;
複製代碼
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 結構體.
};
複製代碼
__block 也能夠標記
__attribute__((NSObject))
應該有byref_keep
和byref_dispose
helper 函數, 使用_Block_object_assign
和_Block_object_dispose
.
由於 block 引用
__block 標記的變量
可能會對他們執行Block_copy()
操做, 變量的底層存儲可能移動到堆中. 在 Objective-C 中, 垃圾收集只在編譯環境中進行, 使用的堆是已收集過的, 不須要進一步的操做. 不然在其做用域的全部轉義或終止時編譯器必須發出一個調用爲__block變量
釋放堆存儲:
_Block_object_dispose(&_block_byref_foo, BLOCK_FIELD_IS_BYREF);
複製代碼
block 嵌套 block 的狀況下, 內部block 引入的任何變量都會被引入到全部封閉範圍, 即便沒有使用, 這包括 const 和 __block 的方式引入.
objects
應以__attribute__((NSObject))
對待. 全部的copy_helper
,dispose_helper
,byref_keep
, andbyref_dispose
helper 函數都應該使用_Block_object_assign
and_Block_object_dispose
. 使用-retain
和-release
不會生成任何其餘代碼.
編譯器在合成屬性
setter
和getter
時將塊視爲對象,在以與對象相同的方式 生成 垃圾收集 strong 和 weak 信息 時將它們描述爲對象,並將以與對象相同的方式 發出 強弱寫入屏障分配。
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:
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));
複製代碼
一個 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 方法描述在
/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);
複製代碼