文章目錄
關於 block
塊的實現原理,以及對外部變量的拷貝和引用問題。
block文檔 做了詳細說明,這裏再複習一遍,並以自己的理解方式寫出。
block文檔 描述了塊的Apple ABI
實現規範,其實就是編譯器對 block
的轉化實現,去了解一個 block
聲明時,編譯器是怎麼構建的。
block的結構體
這個ABI
的第一個發行版本是在Mac OS X 10.6
中找到的,稱爲10.6.ABI
。從2010年3月16日
起,第二個版本,必要時將稱爲ABI.2010.3.16
編譯器會考慮runtime運行時的需要
和各種引用關係
來定義block
的ABI
,也就是說,編譯器會根據上下文,引入的參數,來定義不同的ABI
,(我們可以通過-rewrite-objc
來將OC
文件編譯成cpp實現
來證實),一個block
的結構體如下:
struct Block_literal_1 {
void *isa; // initialized to &_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;
// imported variables
};
isa
可以看到block
被設計成一個對象,可以相應消息。
flag
字段用於表示編譯器生成的block
的“類型”
,後面有說明,其枚舉如下:
對於 ABI.2010.3.16
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 compatibility 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),
};
在10.6.ABI
,(1<<29)
通常被設置,並且總是被runtime
忽略(它是一個轉換標記,在轉換之後沒有被刪除
)。該位現在與 (1<<30)
成對出現,並表示爲對(3<<29)
,以下是有效位設置的組合,還有其意義:
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 convention, presence of signature field
case (3<<29): ABI.2010.3.16, stret calling convention, presence of signature field,
}
這裏不理解 flag
沒事,先接着看。
沒有引入變量的block
對於以下 block
塊的實現
^ { printf("hello world\n"); }
在32位系統中,編譯會將其實現如下:
struct __block_literal_1 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_1 *);
struct __block_descriptor_1 *descriptor;
};
void __block_invoke_1(struct __block_literal_1 *_block) {
printf("hello world\n");
}
static struct __block_descriptor_1 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1) };
有了這些“前置”
,這個 block
的聲明就如下:
struct __block_literal_1 _block_literal = {
&_NSConcreteStackBlock,
(1<<29), <uninitialized>,
__block_invoke_1,
&__block_descriptor_1
};
可以見得,這裏的flag
就是 1<<29
當block
以static常量修飾時,那麼它的實現會是:
struct __block_literal_1 __block_literal_1 = {
&_NSConcreteGlobalBlock,
(1<<28)|(1<<29), <uninitialized>,
__block_invoke_1,
&__block_descriptor_1
};
即flag
添加了 BLOCK_IS_GLOBAL
表示這是一個全局的。
引入變量的block
變量如果沒有__block
修飾,則會自動拷貝一份const
值到 block
結構體中,不再是之前的那個變量。這也是我們需要修改 block
外的值時,必須使用__block
前綴的原因。
如果使用了__block
修飾,編譯器則會將指針複製,並將其包含到一個結構體(這裏就叫A
吧)中,然後編譯器生成的 block
的結構體就包含這個A
引入常量
int x = 10;
void (^vv)(void) = ^{ printf("x is %d\n", x); }
x = 11;
vv();
這段代碼輸出則是x is 10
,因爲拷貝的是值
,編譯器會編譯爲:
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) };
可以見得 const int x
則複製了x
的值,此x
非彼x
。
然後 block
結構體的定義:
struct __block_literal_2 __block_literal_2 = {
&_NSConcreteStackBlock,
(1<<29), <uninitialized>,
__block_invoke_2,
&__block_descriptor_2,
x
};
對於這樣的常量拷貝形式,是不需要 Runtime Helper Functions
的.
Runtime Helper Functions
就是用來支持runtime
機制的,因爲一個對象NSObject
會調用object_release
來釋放,而block
賦值的變量指針對象並沒有在這個範疇內,所以需要 Runtime Helper Functions
,使得runtime
能夠管理其引用關係並及時釋放。
引入block
需要copy and dispose helper functions
的第一種情況是在導入block
本身的情況下。在這種情況下,需要copy_helper函數
和dispose_helper函數
。copy_helper
函數既傳遞現有的基於堆棧的指針
,也傳遞指向新堆的指針
,它應該回調到runtime
中,對block
中導入的字段
實際執行copy
操作。運行時的方法都是在 Runtime Helper Functions(後續說明)
中描述的。
看下面這個例子
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);
}
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,
};
struct __block_literal_3 *const existingBlock;
即拷貝了一個 existingBlock
,不再是之前那個了,那麼會在runtime
中,對existingBlock
中導入的字段
實際執行copy
操作。
編譯器會編譯爲:
struct __block_literal_4 _block_literal = {
&_NSConcreteStackBlock,
(1<<25)|(1<<29), <uninitialized>
__block_invoke_4,
& __block_descriptor_4
existingBlock,
};
1<<25
表示 BLOCK_HAS_COPY_DISPOSE
,表示需要輔助函數 helper functions
處理runtime
的引用計數相關(或者更多
)。
引入 attribute((NSObject)) 變量
GCC
在結構指針
上引入了_attribute__((NSObject))
來表示“這是一個對象”
這很有用,因爲許多低層數據結構
都聲明爲不透明的結構指針
,例如CFStringRef、CFArrayRef
等
例如下面這部分代碼,聲明一個block foo
struct Opaque *__attribute__((NSObject)) objectPointer = ...;
...
void (^foo)(void) = ^{ CFPrint(objectPointer); };
將會創建helper
方法,這個拷貝的helper function
將由編譯器創建,而且應該使用_Block_object_assign
這個運行時方法,然後在釋放時,回到用 _Block_object_dispose
,這也是和 runtime
關聯的方法,相當於NSObject
對象的引用以及釋放。
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
修飾的變量綁定到生成的 block
中,但會包裹一層結構放在 block
中,這個結構就是下面的_block_byref_<name>
:
byref 意思爲指針引用
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 functions
。
在“C”
級別,只有類型爲Block
的變量或標記有_attribute__((NSObject))
的變量需要輔助函數
。在Objective-C
中,對象
需要輔助函數
,而在c++
中,基於堆棧
的對象
需要輔助函數
。需要輔助函數
的變量
使用以下形式:
輔助函數
這裏應該就是處理引用計數相關的工作,所以對象的結構都需要。
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 pointer
被設置爲這個閉包結構的開始size
字段初始化爲閉包結構的總大小
。- 如果不需要輔助函數,則
flags
字段設置爲0
,如果需要,則設置爲(1<<25)
。 - 輔助函數被初始化(
如果存在
)。 變量本身
被設置爲其初始值
。isa
字段被設置爲NULL
。
訪問__block的變量(聲明範圍內)
前面說了 __block
修飾的變量會被編譯器轉義爲_block_byref_<name>
,那麼當我們訪問它時,又有什麼不同呢? 看下面這段代碼
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;
那麼問題又來了,對於需要引用計數的對象呢?對的,是應該就需要helper functions
了
如下代碼:
__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的變量(block內)
我們知道 __block
會直接拷貝指針引用
,所以 __block
聲明的變量都必須實現 helper fuctions
以便於運行時進行拷貝
和釋放
指針,利用_Block_object_assign
和 _Block_object_dispose
。
例如:
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 };
然後block
初始化爲:
struct _block_byref_i 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,
};
引入的__attribute__((NSObject)) __block 變量
__attribute__((NSObject)) __block
修飾的變量,應該也具有 helper function
,和 __block
修飾的變量一樣。
block 的釋放
因爲引用了_block變量
的block
可能會執行Block_copy()
,所以這些變量的底層存儲
可能會移動到堆
中。在Objective-C
垃圾收集中,只有編譯環境中使用的堆
纔是垃圾收集
,不需要進一步的操作。否則,編譯器必須發出一個調用,以便在所有的轉義
或終止作用域時
釋放任意的堆
存儲。調用應該是:
_Block_object_dispose(&_block_byref_foo, BLOCK_FIELD_IS_BYREF);
block 嵌套
block A
中可以包含 block B
,所以按之前所說,block A
結構中可能包含一個成員 _block_literal (爲B)
,所有B
中包含的常量
和變量
都將會被拷貝到block A
即使沒有被使用。這也包括const常量
以及block塊
Object-C擴展
block中引入一個NSObject對象
對象應該被看作是_attribute__((NSObject))
變量;所有的copy_helper、dispose_helper、byref_keep
和byref_dispose
幫助函數都應該使用_Block_object_assign
和_Block_object_dispose
。不應該生成使用*-retain
或*-release
方法的代碼。
block當作爲一個對象
編譯器在合成屬性setter
和getter
時將block
視爲對象
,和對象一樣能夠進行強引用和弱引用
__weak __block支持
Objective-C
(和objective - c++
)支持在block
變量上的_weak
屬性。通常情況下,編譯器會使用Objective-C運行時
的helper fucntion
調用objc_assign_weak
和objc_read_weak
。這兩種方法都應該用於對所有__weak __block
變量的讀寫:
對於常量 i
objc_read_weak(&block->byref_i->forwarding->i)
_weak
變量存儲在_block_byref_foo
結構中,Block
有copy
和dispose
的helper
函數,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);
對於對象
和常量的區別除了拷貝指針外,在於flag
不同,使用 BLOCK_FIELD_IS_OBJECT
_Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_OBJECT | BLOCK_BYREF_CALLER);
例如:
__block __weak id obj = <initialization expression>;
functioncall(^{ [obj somemessage]; });
會被轉化爲:
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);
};
__weak __block
修飾的則是flag
的不同。
對於block
使用 BLOCK_FIELD_IS_BLOCK
_Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
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;
};
void __block_invoke_5(struct __block_literal_5 *_block) {
[objc_read_weak(&_block->byref_obj->forwarding->captured_obj) somemessage];
}
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);
}
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);
}
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 };
對象
和block
兩者初始化都爲
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, // a reference to the on-stack structure containing "captured_obj"
};
functioncall(_block_literal->invoke(&_block_literal));
C++支持
拷貝內容
當一個C++
對象存在於block
塊中時,flag
則會標記爲(1<<26)
,當然同時還有(1<<25)
{
FOO foo;
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) {
FOO_ctor(&dst->foo, &src->foo);
}
void __block_dispose_10(struct __block_literal_10 *src) {
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 };
然後構建爲:
{
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,
};
comp_ctor(&_block_literal->foo, &foo); // const copy into stack version
struct __block_literal_10 &block = &_block_literal; // assign literal to block variable
block->invoke(block); // invoke block
comp_dtor(&_block_literal->foo); // destroy stack version of const block copy
comp_dtor(&foo); // destroy original version
}
拷貝指針
如果添加了__block
前綴
__block FOO blockStorageFoo;
那麼構建時就需要
FOO_ctor(& _block_byref_blockStorageFoo->blockStorageFoo);
析構:
FOO_dtor(& _block_byref_blockStorageFoo->blockStorageFoo);
這裏指的注意的是並沒有使用
forwarding
指針
編譯器生成的helper fuctions
如下:
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 functions
可以在 /usr/local/include/Block_private.h.
查看描述。
helper fuctions
應該對每個block
調用
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<apropos>);
和
_Block_object_dispose(->target, BLOCK_FIELD_<apropos>);
apropos
的枚舉如下:
enum {
BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
BLOCK_FIELD_IS_BLOCK = 7, // a block variable
BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
BLOCK_FIELD_IS_WEAK = 16, // declared __weak
BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
};
其含義和使用上面的例子已經用到了
BLOCK_FIELD_IS_OBJECT
表示對象
BLOCK_FIELD_IS_BLOCK
表示一個block對象
BLOCK_FIELD_IS_BYREF
表示指針引用,意味着拷貝指針
BLOCK_FIELD_IS_WEAK
表示__weak屬性
BLOCK_BYREF_CALLER
表示使用helper functions
實現copy/dispose
方法,兼容runtime
附上源代碼中的代碼摘要:
/* 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.
*/
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:
*/
void _Block_object_dispose(const void *object, const int flags);