Block原理(二)- 用白話說說底層源碼,不扯代碼

之前有一篇關(guān)于block的源碼探究分析 Block原理(一),時(shí)至今日,總覺的那篇文章說得不夠流暢,今天打算從頂層設(shè)計(jì)的角度試著拆解下block的設(shè)計(jì)思想,拗腦的源碼部分就不必再次觸碰了,盡量保障這篇文章閱讀下來不會(huì)感覺不舒服

block的頂層結(jié)構(gòu)

摒棄圖文,最主要的是能說得明白,而不是看得明白,一些關(guān)鍵名字我代替源碼中的復(fù)雜命名,用別名代替,姑且往后看,后面會(huì)拆解為什么要這樣指代別名

先從最全的結(jié)構(gòu)說起,也就是 block捕獲 __block 修飾的變量說起

注意層級(jí)關(guān)系,縮進(jìn)的表示 屬于上一層級(jí)

  • Block_Struct (我起的別名,為了指代方便)
    • Block_ByRef (用__block 修飾的變量就會(huì)產(chǎn)生這個(gè)結(jié)構(gòu))
      • forwarding (指向一塊堆空間,后面會(huì)拆解)
      • var_ptr (捕獲的變量,是個(gè)指針)
    • Block_Layout
      • isa (block類別,GlobalBlock/StackBlock/MallocBlock)
      • func_ptr (函數(shù)入口指針,就是上層代碼中那個(gè) {} 部分了)

Block_Struct這個(gè)結(jié)構(gòu) 就是block的精髓了

  1. 首先會(huì)在棧上構(gòu)建一個(gè)這樣的結(jié)構(gòu)

    構(gòu)造 Block_ByRef

    Block_ByRef 捕獲變量 var(__block修飾的變量), var_ptr 捕獲的是 var的指針

    構(gòu)造 Block_Layout

    isa 為 StackBlock(也就是棧block)

    func_ptr 指向 函數(shù)入口,也就是執(zhí)行{}部分的入口函數(shù)地址

以上都是??臻g上的行為

一旦 上層代碼中存在 block傳參, 就會(huì)

  1. 堆上開辟空間 (注意: 開辟空間 發(fā)生在堆上)

    構(gòu)造 Block_ByRef

    var_ptr = 棧Block_ByRef.var_ptr (棧上的值賦值過來)

    棧Block_ByRef 中的 forwarding 指向 這個(gè) 堆Block_ByRef 空間

    forwarding 也指向 自己這個(gè) 堆Block_ByRef 空間 (細(xì)細(xì)品一下)

構(gòu)造 Block_Layout

isa = MallocBlock (也就是堆block)

func_ptr = 棧Block_ByRef.func_ptr

上層代碼中block的暗行為

上層語言中使用block,經(jīng)常會(huì)傳參,這個(gè)傳參的過程 就是 Block_Struct 的拷貝過程

但不是單純的Block_Struct指針拷貝,而是棧上額外創(chuàng)建一個(gè) Block_Struct 結(jié)構(gòu)

新創(chuàng)建的 Block_Struct 成員Block_Byref是塊堆內(nèi)存 (把棧上的 var_ptr 拷貝到這個(gè)堆內(nèi)存上, forwarding 指向 這塊堆內(nèi)存)

成員 Block_Layout 也指向堆空間 (把棧上的 func_ptr 拷貝過來)

如此 導(dǎo)致什么樣的效果

在上層高級(jí)語言中,表現(xiàn)出來就是

在block內(nèi)部訪問 block外定義的變量, 與在block外部訪問 變量,能訪問到同一個(gè),

區(qū)別就是,外部是在棧上訪問, 內(nèi)部是在堆上訪問

外部訪問 - 棧A:Block_Struct -> 棧A:Block_Byref(棧) -> forwarding -> 堆空間 -> 變量var指針

內(nèi)部訪問 - 棧B:Block_Struct -> 棧B:Block_Byref(堆) -> forwarding -> 堆空間 -> 變量var指針

最終 訪問到了同一塊 堆內(nèi)存, 無論內(nèi)部還是外部,訪問修改的都是同一塊內(nèi)存,所以就沒什么問題了

block體執(zhí)行

block定義之后,關(guān)鍵還是要執(zhí)行的

在當(dāng)前的棧Block_Layout里調(diào)用 func_ptr, 與 被拷貝到別處的 堆Block_Layout 里調(diào)用 func_ptr 效果也是一樣的,不管在哪兒調(diào)用,func_ptr 入口函數(shù)地址 都是那一個(gè)

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

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

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