block的底層實現(xiàn)結構

http://blog.csdn.net/jasonblog/article/details/7756763

這篇文章寫得不錯理郑,我梳理一下悲敷。馁龟。怨酝。

首先block用Apple文檔的話來說傀缩,“A block is an anonymous inline collection of code, and sometimes also called a "closure".

一個block是一個匿名內聯(lián)代碼的集合,有時候也叫”closure“凫碌。

但這幾句話寫得比較籠統(tǒng)扑毡,block到底是什么呢?

block提供了一種新的方式進行回調盛险,并且用block進行回調還可以直接訪問局部變量瞄摊,這是一般的函數做不到的勋又。

這份文檔中提到block的幾種適用場合:任務完成時回調處理,消息監(jiān)聽回調處理换帜,錯誤回調處理楔壤,枚舉回調,視圖動畫惯驼、變換蹲嚣,排序。

那么實際上block到底在由底層表現(xiàn)為什么呢祟牲?

其實也是一個結構體(下圖)隙畜,所謂的__main_block_impl_0就是block的具體實現(xiàn),這是最簡單的block的實現(xiàn)说贝,既不需要操作block外的變量议惰。

block結構體包含了__block_impl

由此,一個block就是一個包含了一系列信息的結構體乡恕,包含函數指針言询,類對象的指針,描述信息等等傲宜。

那么稍微復雜一點的block呢运杭?比如操作了block外的變量的block是什么樣的呢?

看到圖中的i了嗎函卒,這就是block外部的變量辆憔,只不過這是不能修改只能訪問。

那為什么不能修改只能訪問呢?因為i傳進來只是進行了值傳遞谆趾,所以block所包含的函數和main函數的作用域是不同的躁愿,你要是修改了,就無法保證內部和外部的數據一致性沪蓬。我們當然可以把i從int換成某個指針變量來實現(xiàn)局部變量的修改。

不過block常常用作回調来候,所以假如block還沒執(zhí)行到跷叉,但是外部函數已經從棧彈出,那這樣再用指針訪問不僅沒有意義营搅,更有可能造成非法訪問的錯誤云挟。

所以在這兒不允許block做修改局部變量。

那么转质,到底怎樣才能修改局部變量呢园欣?

1.全局變量、靜態(tài)全局變量是可以在block中直接進行修改的休蟹,就不存在上面說的可能產生的問題沸枯。

2.在局部變量前面加上__block 指示符日矫。

第1個很好理解,第2個是什么意思呢绑榴?

下圖是一個__block變量對應的結構體

由第一個成員__isa指針也可以知道__Block_byref_i_0也可以是NSObject哪轿。

第二個成員__forwarding指向一個__Block_byref_i_0結構,這個很重要翔怎。

最后一個成員是目標存儲變量i窃诉。


而此時block變成下面這樣


可以看到,i-__forwarding初始化是指向了自己赤套,為什么要指向自己飘痛?指向自己是沒有意義的,只能說有時候需要指向另一個__block結構容握。

對應的函數__main_block_func_0(block所指向的函數)如下:

亮點是__Block_byref_i_0指針類型變量i敦冬,通過其成員變量__forwarding指針來操作另一個成員變量。 為什么要這么做呢唯沮?待會兒再說脖旱。

先解答為什么可以修改局部變量的問題:

通過這樣看起來有點復雜的改變,我們可以修改變量i的值介蛉。但是問題同樣存在:__Block_byref_i_0類型變量i仍然處于棧上萌庆,當block被回調執(zhí)行時,變量i所在的棧已經被展開币旧,怎么辦践险?

在這種關鍵時刻,__main_block_desc_0站出來了:

此時吹菱,__main_block_desc_0多了兩個成員函數:copy和dispose巍虫,分別指向__main_block_copy_0__main_block_dispose_0

當block從棧上被copy到堆上時鳍刷,會調用__main_block_copy_0將__block類型的成員變量i從棧上復制到堆上占遥;而當block被釋放時,相應地會調用__main_block_dispose_0來釋放__block類型的成員變量i输瓜。


那么現(xiàn)在來解決為什么要通過__forwarding來操作局部變量瓦胎。

因為變量一會在棧上,一會在堆上尤揣,那如果棧上和堆上同時對該變量進行操作搔啊,怎么辦?

這時候北戏,__forwarding的作用就體現(xiàn)出來了:當一個__block變量從棧上被復制到堆上時负芋,棧上的那個__Block_byref_i_0結構體中的__forwarding指針也會指向堆上的結構。

所以實際上修改的都是堆上的__Block_byref_i_0結構體嗜愈,main函數釋放的時候旧蛾,只是釋放了棧上的東西莽龟。而所有的對局部變量的修改都早已經轉移到堆上了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末蚜点,一起剝皮案震驚了整個濱河市轧房,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绍绘,老刑警劉巖奶镶,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異陪拘,居然都是意外死亡厂镇,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門左刽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捺信,“玉大人,你說我怎么就攤上這事欠痴∑浚” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵喇辽,是天一觀的道長掌挚。 經常有香客問我,道長菩咨,這世上最難降的妖魔是什么吠式? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮抽米,結果婚禮上特占,老公的妹妹穿的比我還像新娘。我一直安慰自己云茸,他們只是感情好是目,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著查辩,像睡著了一般胖笛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宜岛,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音功舀,去河邊找鬼萍倡。 笑死,一個胖子當著我的面吹牛辟汰,可吹牛的內容都是我干的列敲。 我是一名探鬼主播阱佛,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼戴而!你這毒婦竟也來了凑术?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤所意,失蹤者是張志新(化名)和其女友劉穎淮逊,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體扶踊,經...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡泄鹏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了秧耗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片备籽。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖分井,靈堂內的尸體忽然破棺而出车猬,到底是詐尸還是另有隱情,我是刑警寧澤尺锚,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布珠闰,位于F島的核電站,受9級特大地震影響缩麸,放射性物質發(fā)生泄漏铸磅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一杭朱、第九天 我趴在偏房一處隱蔽的房頂上張望阅仔。 院中可真熱鬧,春花似錦弧械、人聲如沸八酒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羞迷。三九已至,卻和暖如春画饥,著一層夾襖步出監(jiān)牢的瞬間衔瓮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工抖甘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留热鞍,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像薇宠,于是被迫代替她去往敵國和親偷办。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內容