Block詳解-2:block的實(shí)質(zhì)以及實(shí)現(xiàn)

Block的實(shí)質(zhì)以及實(shí)現(xiàn)

Block的實(shí)現(xiàn)是通過結(jié)構(gòu)體的方式實(shí)現(xiàn),在編譯的過程中,將Block生成對應(yīng)的結(jié)構(gòu)體,在結(jié)構(gòu)體中記錄Block的匿名函數(shù),以及使用到的自動變量,在最后的使用中,通過Block結(jié)構(gòu)體實(shí)例訪問成員中存放的匿名函數(shù)地址調(diào)用匿名函數(shù),并將自身作為參數(shù)傳遞。
所謂的匿名函數(shù)也不是完全匿名的,編譯時還是會按照匿名函數(shù)所在的方法、Block、順序命名,并記錄到Block結(jié)構(gòu)體中。

將含有Block語法的源代碼變換為C++源代碼。

clang -rewrite-objc 源代碼文件名

執(zhí)行該命令后,會在源代碼文件路徑下生成一個與源代碼文件名稱相同后綴為.cpp的文件。

源文件和轉(zhuǎn)換后的文件.png

源代碼

int main() {
void (^block) (void) = ^ {
    printf("block\n");
};
block();
}

轉(zhuǎn)換后的代碼,將其中有效的信息提取出來。 如果看的比較暈可以結(jié)合文章末尾圖一起食用,效果更好。

struct __block_impl { 
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

struct __main_block_impl_0 {
 struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

static void __main_block_func_0(struct __main_block_impl_0 *__cself)     {

        printf("block\n");
    }

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

int main() {
    void (*block) (void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
變換后的源代碼中也含有相同的表達(dá)式,通過Block使用的匿名函數(shù)實(shí)際上被作為最為簡單的C語言函數(shù)來處理,另外,根據(jù)Block語法所屬的函數(shù)名(此處為main)和該Block語法所在該函數(shù)出現(xiàn)的順序值(此處為0)來給經(jīng)clang變換的函數(shù)命名。
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

    printf("block\n");
}

參數(shù)__cself 為 __main_block_impl_0 結(jié)構(gòu)體的指針。

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;

//構(gòu)造函數(shù)
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

第一個成員變量impl:__block_impl結(jié)構(gòu)體。所有block結(jié)構(gòu)體中都存在的成員。記錄著基本信息,isa類似對象中的isa指針,F(xiàn)uncPtr記錄著block對應(yīng)的實(shí)現(xiàn)函數(shù)。

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

第二個成員變量Desc:__main_block_desc_0結(jié)構(gòu)體。

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
}__main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

初始化結(jié)構(gòu)體的__main_block_impl_0結(jié)構(gòu)體構(gòu)造函數(shù)

  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }

__main_block_impl_0結(jié)構(gòu)體構(gòu)造函數(shù)構(gòu)造函數(shù)的調(diào)用:

void (*block) (void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

轉(zhuǎn)換下:

struct _main_block_impl_0 temp = 
__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA);
struct _main_block_impl_0 *block = &temp;

該源代碼將__main_block_impl_0結(jié)構(gòu)體類型的自動變量,即棧上生成的__main_block_impl_0結(jié)構(gòu)體實(shí)例的指針,賦值給__main_block_impl_0結(jié)構(gòu)體指針類型的變量block。
其中__main_block_impl_0構(gòu)造函數(shù)的參數(shù)一為:Block語法轉(zhuǎn)換的C語言函數(shù)指針。參數(shù)二是作為靜態(tài)全局變量初始化的_main_block_desc_0結(jié)構(gòu)體實(shí)例指針。

以下為_main_block_desc_0結(jié)構(gòu)體實(shí)例初始化部分代碼:

__main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

使用__main_block_impl_0結(jié)構(gòu)體實(shí)例的大小進(jìn)行出初始化。

使用該block:

  ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

去掉轉(zhuǎn)換部分等同:

(*block->impl.FuncPtr)(blcok);

簡單的函數(shù)指針調(diào)用函數(shù),由Block語法轉(zhuǎn)換的__main_block_func_0函數(shù)指針被賦值成員變量FuncPtr中,另外也說明了。_main_block_func_0函數(shù)的參數(shù)_cself指向Block值。在調(diào)用該函數(shù)的源代碼中可以看出Block正是作為參數(shù)進(jìn)行傳遞。

  • Block的實(shí)質(zhì)即為Objective-C的對象。

最后奉上一張大圖:

原圖

block詳解.png

待續(xù)。

參考

《Objective-C高級編程》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容