Objective-C之Blocks(二)

前言

Objective-C之Blocks(一)中扣孟,說(shuō)明了Block的一些用法和特性牲证。其中講到Block的三種特性:

  • 截獲自動(dòng)變量
  • __block說(shuō)明符
  • 截獲的自動(dòng)變量

但是我們還是不知道Block的實(shí)質(zhì)和這些特性是如何實(shí)現(xiàn)的绕娘。本文將介紹Block的本質(zhì)。

Block本質(zhì)

想要了解Block的本質(zhì)褥蚯,我們就需要利用clang(LLVM編譯器)將代碼轉(zhuǎn)換為C++代碼閱讀译秦。我們先在終端中進(jìn)入main.m文件路徑嚷那,在終端中輸入

clang -rewrite-objc main.m(文件名字)

轉(zhuǎn)換后的文件變得很長(zhǎng)抚垄,是因?yàn)榫幾g器對(duì)頭文件的處理齐遵,我們可以忽略不看戒良,直接在文件里面搜索int main体捏,我們可以看到轉(zhuǎn)換過(guò)后的main函數(shù),和Block的實(shí)現(xiàn)糯崎。

int main函數(shù)

分析main函數(shù)几缭,我們可以看到一個(gè)Block類(lèi)型變量,其值是一個(gè)__main_block_impl_0結(jié)構(gòu)體,在調(diào)用該結(jié)構(gòu)體構(gòu)造函數(shù)的時(shí)候沃呢,傳入了兩個(gè)參數(shù)__main_block_func_0函數(shù)指針和__main_block_desc_0_DATA結(jié)構(gòu)體年栓。

__main_block_func_0函數(shù)

觀察__main_block_func_0函數(shù)

__main_block_func_0函數(shù)

在函數(shù)中參數(shù):__cself和OC中的self相同。
觀察函數(shù)我們發(fā)現(xiàn)薄霜,其中有NSLog某抓。由此我們可以推測(cè)出竿刁,__main_block_func_0函數(shù)是我們自己定義的函數(shù)主體。我們將Block中的代碼塊更改成for循環(huán)來(lái)驗(yàn)證我們的猜想搪缨。

main函數(shù)

轉(zhuǎn)換后的__main_block_func_0函數(shù)

轉(zhuǎn)換后的`__main_block_func_0`函數(shù)

猜想正確食拜,所以,__main_block_func_0函數(shù)代表了Block中副编,我們自己定義的代碼塊负甸。Block通過(guò)將此函數(shù)指針傳遞給__main_block_impl_0結(jié)構(gòu)體指針來(lái)實(shí)現(xiàn)調(diào)用代碼塊。

__main_block_desc_0_DATA結(jié)構(gòu)體

觀察__main_block_desc_0_DATA結(jié)構(gòu)體

__main_block_desc_0_DATA函數(shù)

其中有2個(gè)成員變量痹届,一個(gè)是reserved呻待,它代表今后版本升級(jí)所需要的區(qū)域;還有一個(gè)是Block_size队腐,它代表Block大小蚕捉。而B(niǎo)lock的大小是__main_block_impl_0結(jié)構(gòu)體的大小。

__main_block_impl_0結(jié)構(gòu)體

觀察__main_block_impl_0結(jié)構(gòu)體

__main_block_impl_0結(jié)構(gòu)體

該結(jié)構(gòu)體中寫(xiě)入了其構(gòu)造函數(shù)柴淘,所以看起來(lái)比較復(fù)雜迫淹。去掉構(gòu)造函數(shù)后,其聲明如下:

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

第一個(gè)成員變量是__block_impl結(jié)構(gòu)體为严;第二個(gè)成員變量是__main_block_desc_0結(jié)構(gòu)體指針敛熬,此結(jié)構(gòu)體前文已經(jīng)說(shuō)明過(guò),不再贅述第股。
關(guān)于__main_block_impl_0結(jié)構(gòu)體的構(gòu)造函數(shù)应民,傳入的三個(gè)參數(shù):fpdesc夕吻、flags分別代表函數(shù)指針(此函數(shù)指針即為我們自已定義的代碼塊)诲锹、__main_block_desc_0結(jié)構(gòu)體指針一個(gè)標(biāo)志位(一般為0)

__block_impl結(jié)構(gòu)體

下面我們著重來(lái)看__block_impl結(jié)構(gòu)體涉馅,在cpp文件中搜索__block_impl

__block_impl結(jié)構(gòu)體

此結(jié)構(gòu)體中有4個(gè)成員變量:

  • isa指針 : 指向一個(gè)類(lèi)對(duì)象
  • Flags : 某種標(biāo)志
  • Reserved : 今后版本升級(jí)所需的區(qū)域
  • FuncPtr : 函數(shù)指針归园,指向我們自己的代碼塊

了解了__block_impl結(jié)構(gòu)體,所以我們可以將__main_block_impl_0結(jié)構(gòu)體寫(xiě)成如下形式:

struct __main_block_impl_0 {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
  struct __main_block_desc_0* Desc;
};

該結(jié)構(gòu)體根據(jù)構(gòu)造函數(shù)會(huì)像下面這樣初始化:

isa = &_NSConcreateStackBlck;
Flags = 0;
Reserved = 0;
FuncPtr = __main_block_func_0;
Desc = &__main_block_desc_0_DATA;

其中_NSConcreateStackBlck代表一個(gè)對(duì)象控漠,具體的在下一部分中講解蔓倍。

Block的使用

Block的使用為:

blk();

可轉(zhuǎn)換為以下形式:

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

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

(*blk->impl.FuncPtr)(blk);

這是簡(jiǎn)單的使用函數(shù)指針調(diào)用函數(shù)悬钳,傳遞的參數(shù)為block本身盐捷,也證明的前文所述__cself和OC中的self相同。

總結(jié)

  • 在我們創(chuàng)建Block的時(shí)候默勾,會(huì)生成__main_block_impl_0結(jié)構(gòu)體變量賦值給Block變量碉渡。由于該結(jié)構(gòu)體中存在isa指針,所以使block成為了OC對(duì)象母剥,即該結(jié)構(gòu)體相當(dāng)于基于objc_object結(jié)構(gòu)體的OC類(lèi)對(duì)象結(jié)構(gòu)體滞诺。(關(guān)于isa指針請(qǐng)參見(jiàn):關(guān)于oc運(yùn)行時(shí) isa指針詳解)我們以__main_block_func_0函數(shù)指針(其指向我們自定義的代碼塊所在函數(shù))和__main_block_desc_0_DATA結(jié)構(gòu)體(其保存了今后升級(jí)所需區(qū)域和Block大行蔚肌)來(lái)初始化__main_block_impl_0結(jié)構(gòu)體。通過(guò)過(guò)函數(shù)指針的調(diào)用习霹,我們就實(shí)現(xiàn)了Block的使用朵耕。
    * 本文重點(diǎn)講述Block的本質(zhì),關(guān)于Block的特性淋叶,請(qǐng)參見(jiàn)以后的文章阎曹。
  • 本文重點(diǎn)講述Block的本質(zhì),關(guān)于Block的特性煞檩,請(qǐng)參見(jiàn)Objective-C之Blocks(三)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末处嫌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子斟湃,更是在濱河造成了極大的恐慌熏迹,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凝赛,死亡現(xiàn)場(chǎng)離奇詭異注暗,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)墓猎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)友存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人陶衅,你說(shuō)我怎么就攤上這事屡立。” “怎么了搀军?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵膨俐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我罩句,道長(zhǎng)焚刺,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任门烂,我火速辦了婚禮乳愉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屯远。我一直安慰自己蔓姚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布慨丐。 她就那樣靜靜地躺著坡脐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪房揭。 梳的紋絲不亂的頭發(fā)上备闲,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天晌端,我揣著相機(jī)與錄音,去河邊找鬼恬砂。 笑死咧纠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的泻骤。 我是一名探鬼主播惧盹,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瞪讼!你這毒婦竟也來(lái)了钧椰?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤符欠,失蹤者是張志新(化名)和其女友劉穎嫡霞,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體希柿,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诊沪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了曾撤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片端姚。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖挤悉,靈堂內(nèi)的尸體忽然破棺而出渐裸,到底是詐尸還是另有隱情,我是刑警寧澤装悲,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布昏鹃,位于F島的核電站,受9級(jí)特大地震影響诀诊,放射性物質(zhì)發(fā)生泄漏洞渤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一属瓣、第九天 我趴在偏房一處隱蔽的房頂上張望载迄。 院中可真熱鬧,春花似錦抡蛙、人聲如沸护昧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捏卓。三九已至,卻和暖如春慈格,著一層夾襖步出監(jiān)牢的瞬間怠晴,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工浴捆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蒜田,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓选泻,卻偏偏與公主長(zhǎng)得像冲粤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子页眯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容