11 iOS底層原理 - Block本質(zhì)探究

廢話不多說,老規(guī)矩恬惯,還是來到面試題:

一向拆,block的原理是什么?本質(zhì)是什么樣的酪耳?

帶著疑問亲铡,咋們一起看看block的底層到底長啥樣...

研究本質(zhì),我們常用的手段就是,就是將oc的代碼通過clang編譯成c++的代碼奖蔓,然后通過c++的代碼,看看到底都干了啥讹堤。

一吆鹤,研究block編譯后C++代碼

1. clang編譯

定一個(gè)block及實(shí)現(xiàn),通過clang編譯洲守,看看block底層的數(shù)據(jù)結(jié)構(gòu)是什么疑务??梗醇?

- (void)viewDidLoad {
    [super viewDidLoad];
    
    int age = 18;
    void (^myBlock)(void) = ^{
        NSLog(@"myBlock = %d", age);
    };
    myBlock();
}

利用clang在終端編譯,我的代碼是在ViewController.m里面寫的知允,所以編譯這個(gè).m文件就好

& xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc ViewController.m
2. 查看c++代碼

直接上圖

image.png

通過上圖可以得出:

  1. Block實(shí)現(xiàn)的原理:
    1> Block實(shí)現(xiàn),Block在底層就是一個(gè)指向結(jié)構(gòu)體的指針叙谨,
    2> 調(diào)用block時(shí)温鸽,根據(jù)Block對(duì)應(yīng)的指針找到相應(yīng)的函數(shù),進(jìn)而進(jìn)行調(diào)用手负,并把自己傳進(jìn)去涤垫;
  1. 編譯后的代碼,Block定義部分也就是=右邊的^{}轉(zhuǎn)換中成了一個(gè)函數(shù)竟终,這個(gè)函數(shù)接收三個(gè)參數(shù):
__ViewController__viewDidLoad_block_impl_0(func, desc, age);

這個(gè)函數(shù)到底是什么呢蝠猬??
是一個(gè)返回當(dāng)前結(jié)構(gòu)體類型的函數(shù)(類似于oc中的初始化函數(shù)),
最終將這些信息存儲(chǔ)在了結(jié)構(gòu)體中统捶,這個(gè)結(jié)構(gòu)體中具體有啥呢榆芦?
接著往下看...

3. block底層數(shù)據(jù)結(jié)構(gòu)分析

通過下圖我們分析一下,block底層的數(shù)據(jù)結(jié)構(gòu):

通過圖例喘鸟,可以知道匆绣,最后的isa是指向?qū)ο蟮慕Y(jié)構(gòu)體的。
所以得出結(jié)論:

結(jié)論: block的底層數(shù)據(jù)結(jié)構(gòu)是一個(gè)結(jié)構(gòu)體迷守,本質(zhì)就是一個(gè)OC對(duì)象

那么犬绒,block的內(nèi)存布局,簡單的用下圖就可以表示(紅框圈起來的先不用管兑凿,后面的博客會(huì)講到):

image.png

其他的成員是不是都可以找到的了凯力,下面說下 FuncPtr這個(gè)函數(shù)是干什么的吧

4. Block的本質(zhì)-FuncPtr函數(shù)的調(diào)用

通過已經(jīng)存儲(chǔ)的FuncPtr地址值,找到具體的方法實(shí)現(xiàn)礼华,如圖所示:

image.png

找到的這個(gè)方法咐鹤,就是block的{}里面的所有實(shí)現(xiàn)。

咋們也可以驗(yàn)證下圣絮,這個(gè)FuncPtr到底存的是不是這個(gè)函數(shù)的地址值:

1> 聲明block底層數(shù)據(jù)結(jié)構(gòu)-結(jié)構(gòu)體
struct __block_impl {
  void *isa; // 對(duì)象的isa
  int Flags;
  int Reserved;
  void *FuncPtr; // 指向了block里面的實(shí)現(xiàn) { ... }
};

struct __ViewController__viewDidLoad_block_desc_0 {
  size_t reserved;
  size_t Block_size; // 這個(gè)block得內(nèi)存大小
};

struct __ViewController__viewDidLoad_block_impl_0 {
  struct __block_impl impl; // 直接擁有這個(gè)結(jié)構(gòu)體變量
  struct __ViewController__viewDidLoad_block_desc_0* Desc; // 這是一個(gè)指針祈惶,指向另一個(gè)結(jié)構(gòu)體的變量
  int age;
};

運(yùn)行代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    int age = 18;
    void (^myBlock)(void) = ^
    {
        NSLog(@"myBlock = %d", age);
    };
    // 將myBlock賦值給一個(gè)結(jié)構(gòu)體
    struct __ViewController__viewDidLoad_block_impl_0
    * structBLock =
    (__bridge struct __ViewController__viewDidLoad_block_impl_0 *)myBlock;
    
    myBlock();
}

在myBlock(); 實(shí)現(xiàn)處打個(gè)斷點(diǎn),就可以找到地址值了,如下圖所示:

image.png

通過調(diào)試捧请,可以看出:block內(nèi)存中存儲(chǔ)的地址值凡涩,就是這個(gè){}里面的地址值。

注意:右側(cè)的堆棧信息是打開了匯編調(diào)試疹蛉,具體如圖所示:

image.png

二活箕,Block總結(jié)

  1. Block本質(zhì)是一個(gè)OC對(duì)象,它內(nèi)部也存在一個(gè)isa指針可款,底層數(shù)據(jù)結(jié)構(gòu)是一個(gè)結(jié)構(gòu)體育韩;
    1. Block實(shí)現(xiàn)的原理:
      1> Block實(shí)現(xiàn),Block在底層就是一個(gè)指向結(jié)構(gòu)體的指針闺鲸,
      2> 調(diào)用block時(shí)筋讨,根據(jù)Block對(duì)應(yīng)的指針找到相應(yīng)的函數(shù),進(jìn)而進(jìn)行調(diào)用摸恍,并把自己傳進(jìn)去悉罕。

三,回答文章開頭的面試題

一误墓,block的原理是什么蛮粮?本質(zhì)是什么樣的?
原理:
1> Block實(shí)現(xiàn)谜慌,Block在底層就是一個(gè)指向結(jié)構(gòu)體的指針然想,
2> 調(diào)用block時(shí),根據(jù)Block對(duì)應(yīng)的指針找到相應(yīng)的函數(shù)欣范,進(jìn)而進(jìn)行調(diào)用变泄,并把自己傳進(jìn)去;
本質(zhì):
Block本質(zhì)是一個(gè)OC對(duì)象恼琼,它內(nèi)部也存在一個(gè)isa指針妨蛹,底層數(shù)據(jù)結(jié)構(gòu)是一個(gè)結(jié)構(gòu)體。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末晴竞,一起剝皮案震驚了整個(gè)濱河市蛙卤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌噩死,老刑警劉巖颤难,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異已维,居然都是意外死亡行嗤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門垛耳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栅屏,“玉大人飘千,你說我怎么就攤上這事≌祸ǎ” “怎么了护奈?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長甫恩。 經(jīng)常有香客問我逆济,道長,這世上最難降的妖魔是什么磺箕? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮抛虫,結(jié)果婚禮上松靡,老公的妹妹穿的比我還像新娘。我一直安慰自己建椰,他們只是感情好雕欺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著棉姐,像睡著了一般屠列。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伞矩,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天笛洛,我揣著相機(jī)與錄音,去河邊找鬼乃坤。 笑死苛让,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的湿诊。 我是一名探鬼主播狱杰,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼厅须!你這毒婦竟也來了仿畸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤朗和,失蹤者是張志新(化名)和其女友劉穎错沽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體例隆,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡甥捺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镀层。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镰禾。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡皿曲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吴侦,到底是詐尸還是另有隱情屋休,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布备韧,位于F島的核電站劫樟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏织堂。R本人自食惡果不足惜叠艳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望易阳。 院中可真熱鬧附较,春花似錦、人聲如沸潦俺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽事示。三九已至早像,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肖爵,已是汗流浹背卢鹦。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遏匆,地道東北人法挨。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像幅聘,于是被迫代替她去往敵國和親凡纳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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