Block詳解-2:block的實質以及實現

Block的實質以及實現

Block的實現是通過結構體的方式實現吻谋,在編譯的過程中妻导,將Block生成對應的結構體嗤瞎,在結構體中記錄Block的匿名函數女器,以及使用到的自動變量酸役,在最后的使用中,通過Block結構體實例訪問成員中存放的匿名函數地址調用匿名函數驾胆,并將自身作為參數傳遞涣澡。
所謂的匿名函數也不是完全匿名的,編譯時還是會按照匿名函數所在的方法丧诺、Block入桂、順序命名,并記錄到Block結構體中驳阎。

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

clang -rewrite-objc 源代碼文件名

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

源文件和轉換后的文件.png

源代碼

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

轉換后的代碼蜘腌,將其中有效的信息提取出來。 如果看的比較暈可以結合文章末尾圖一起食用饵隙,效果更好撮珠。

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);
}
變換后的源代碼中也含有相同的表達式,通過Block使用的匿名函數實際上被作為最為簡單的C語言函數來處理金矛,另外芯急,根據Block語法所屬的函數名(此處為main)和該Block語法所在該函數出現的順序值(此處為0)來給經clang變換的函數命名。
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

    printf("block\n");
}

參數__cself 為 __main_block_impl_0 結構體的指針驶俊。

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;
  }
};

第一個成員變量impl:__block_impl結構體娶耍。所有block結構體中都存在的成員。記錄著基本信息饼酿,isa類似對象中的isa指針榕酒,FuncPtr記錄著block對應的實現函數胚膊。

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

第二個成員變量Desc:__main_block_desc_0結構體。

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)};

初始化結構體的__main_block_impl_0結構體構造函數

  __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結構體構造函數構造函數的調用:

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

轉換下:

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結構體類型的自動變量想鹰,即棧上生成的__main_block_impl_0結構體實例的指針澜掩,賦值給__main_block_impl_0結構體指針類型的變量block。
其中__main_block_impl_0構造函數的參數一為:Block語法轉換的C語言函數指針杖挣。參數二是作為靜態(tài)全局變量初始化的_main_block_desc_0結構體實例指針肩榕。

以下為_main_block_desc_0結構體實例初始化部分代碼:

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

使用__main_block_impl_0結構體實例的大小進行出初始化。

使用該block:

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

去掉轉換部分等同:

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

簡單的函數指針調用函數,由Block語法轉換的__main_block_func_0函數指針被賦值成員變量FuncPtr中惩妇,另外也說明了株汉。_main_block_func_0函數的參數_cself指向Block值。在調用該函數的源代碼中可以看出Block正是作為參數進行傳遞歌殃。

  • Block的實質即為Objective-C的對象乔妈。

最后奉上一張大圖:

原圖

block詳解.png

待續(xù)。

參考

《Objective-C高級編程》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末氓皱,一起剝皮案震驚了整個濱河市路召,隨后出現的幾起案子,更是在濱河造成了極大的恐慌波材,老刑警劉巖股淡,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異廷区,居然都是意外死亡唯灵,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門隙轻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來埠帕,“玉大人,你說我怎么就攤上這事玖绿×泊桑” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵斑匪,是天一觀的道長呐籽。 經常有香客問我,道長秤标,這世上最難降的妖魔是什么绝淡? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任宙刘,我火速辦了婚禮苍姜,結果婚禮上,老公的妹妹穿的比我還像新娘悬包。我一直安慰自己衙猪,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著垫释,像睡著了一般丝格。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上棵譬,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天显蝌,我揣著相機與錄音,去河邊找鬼订咸。 笑死曼尊,一個胖子當著我的面吹牛,可吹牛的內容都是我干的脏嚷。 我是一名探鬼主播骆撇,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼父叙!你這毒婦竟也來了神郊?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤趾唱,失蹤者是張志新(化名)和其女友劉穎涌乳,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體甜癞,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡爷怀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了带欢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片运授。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖乔煞,靈堂內的尸體忽然破棺而出吁朦,到底是詐尸還是另有隱情,我是刑警寧澤渡贾,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布逗宜,位于F島的核電站,受9級特大地震影響空骚,放射性物質發(fā)生泄漏纺讲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一囤屹、第九天 我趴在偏房一處隱蔽的房頂上張望熬甚。 院中可真熱鬧,春花似錦肋坚、人聲如沸乡括。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诲泌。三九已至盲赊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間敷扫,已是汗流浹背哀蘑。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留葵第,地道東北人递礼。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像羹幸,于是被迫代替她去往敵國和親脊髓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容