iOS開發-關於block塊的實現

關於 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運行時的需要各種引用關係來定義blockABI,也就是說,編譯器會根據上下文,引入的參數,來定義不同的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;
};

這個結構體這樣初始化的:

  1. forwarding pointer 被設置爲這個閉包結構的開始
  2. size字段初始化爲閉包結構的總大小
  3. 如果不需要輔助函數,則flags字段設置爲0,如果需要,則設置爲(1<<25)
  4. 輔助函數被初始化(如果存在)。
  5. 變量本身被設置爲其初始值
  6. 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_keepbyref_dispose幫助函數都應該使用_Block_object_assign_Block_object_dispose。不應該生成使用*-retain*-release方法的代碼。

block當作爲一個對象

編譯器在合成屬性settergetter時將block視爲對象,和對象一樣能夠進行強引用和弱引用

__weak __block支持

Objective-C(和objective - c++)支持在block變量上的_weak屬性。通常情況下,編譯器會使用Objective-C運行時helper fucntion調用objc_assign_weakobjc_read_weak。這兩種方法都應該用於對所有__weak __block變量的讀寫:

對於常量 i

objc_read_weak(&block->byref_i->forwarding->i)

_weak變量存儲在_block_byref_foo結構中,Blockcopydisposehelper函數,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);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章