小码哥iOS学习笔记第八天: block的底层结构
生活随笔
收集整理的這篇文章主要介紹了
小码哥iOS学习笔记第八天: block的底层结构
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、最簡單的block
1、最簡單的block結構
^{NSLog(@"this is a block");NSLog(@"this is a block");NSLog(@"this is a block"); }; 復制代碼2、block的調用
^{NSLog(@"this is a block");NSLog(@"this is a block");NSLog(@"this is a block"); }(); 復制代碼void (^block)(void) = ^{NSLog(@"this is a block");NSLog(@"this is a block");NSLog(@"this is a block"); }; block(); 復制代碼二、block的底層結構
- 使用終端cd到main.m文件所在文件夾, 并執行下述命令行
- 將生成的main.cpp文件拖到項目中并打開, 可以看到編譯后的main函數, 可以看到block的定義和調用
- 在main.cpp中還可以找到如下代碼
- 可以看到block在底層的結構是__main_block_impl_0結構體
- block中的代碼塊也封裝成了一個函數__main_block_func_0
- __main_block_impl_0的第一個參數__block_impl結構體如下
- 所以__main_block_impl_0結構體可以看成下圖的樣子, 因為第一個成員變量是isa, 所以block本質就是一個OC對象
- 再看main函數, 將創建block對象時的強制轉換類型刪掉, 可以看到下面的樣子
-
創建__main_block_impl_0時, 傳入兩個參數, 第一個就是封裝了block代碼塊的__main_block_func_0函數的地址, 第二個是block的描述結構體__main_block_desc_0(0,__main_block_impl_0占用內存大小)
-
接著查看__main_block_impl_0的構造函數
- 可以看到__main_block_func_0的函數地址賦值給了__block_impl結構體的成員變量FuncPtr, block的描述賦值給了第二個成員變量Desc
總結: block的本質就是封裝了函數調用以及函數調用環境的OC對象
- block的調用是通過找到impl中的FuncPtr來獲取到__main_block_func_0函數的地址, 然后調用, 同時傳入__main_block_impl_0的地址
- 這里之所以直接使用block->FuncPtr, 而不是block->impl.FuncPtr, 是因為impl是struct __main_block_impl_0的第一個成員變量, 所以impl的地址和block的地址相同
- 所以就可以通過block的指針直接使用FuncPtr
三、帶參數的block的底層結構
- 定義block時, 可以傳入參數
- 使用終端cd到main.m文件所在文件夾, 并執行下述命令行
- 將生成的main.cpp文件拖到項目中并打開, 可以看到編譯后的main函數, 可以看到block的定義和調用
- 刪除類型轉換后, 代碼如下, 調用block時傳入了10和20
四、block的變量捕獲
- 在OC中變量的類型主要使用三種, 分別是auto、static、全局變量, 其中auto和static修飾的是局部變量
- 對這三種類型的變量, block在使用使用時, 會有不同的捕獲方式
1、auto變量捕獲(值捕獲)
- 在OC中, 我們定義的變量, 默認就是auto類型, 離開作用域就會銷毀
- 當block中使用外界的變量時, 就會進行變量捕捉
- 使用終端cd到main.m文件所在文件夾, 并執行下述命令行
- 將生成的main.cpp文件拖到項目中并打開, 可以看到編譯后的block
- 可以發現__main_block_impl_0結構體中多了一個成員變量age, 這個age就是根據main函數中age生成的成員變量
- __main_block_impl_0中的age和main函數中的age是獨立的兩個變量
- block調用時使用的age是__main_block_impl_0的成員變量, 而不是main函數中的age
- 而age的值, 是在block創建時傳入的
- 所以在main函數中, 如果在block定義后修改age的值, 在調用block時, age的值不會改變
- 此時底層結構如下
2、static變量捕獲(指針捕獲)
- 有代碼如下, 使用static修飾age變量
- 底層的__main_block_impl_0中的age類型是指針類型int *
- 說明使用static修飾過的變量, 會把變量的地址捕獲到__main_block_impl_0中
- 此時main函數中, 調用__main_block_impl_0的構造函數時, 傳入的就是age的地址
- 在block調用時, __main_block_func_0函數中也是通過age的地址訪問age的值
- 此時如果在main函數中block定義的后面修改age的值, 那么在block中通過地址訪問的age就是修改之后的值
- 此時底層的調用代碼如下
三、block中使用全局變量(不會捕獲)
- 此時block的底層結構如下, block并沒有捕獲age, 而是直接使用
總結:
block中如果使用了全局變量, 那么這個全局變量不會被捕獲到block中
block調用時, 直接使用全局變量, 所以全局變量的值改變, block中使用的值也會相應改變
- 修改age的值, 在調用block, 可以看到block中打印的值也發生了變化
四、block對auto、static、全局變量捕獲方式
總結:
在block中, 如果使用局部變量, 那么就會捕獲該變量
在block中, 如果使用全局變量, 那么就不會捕獲該變量, 而是直接使用
轉載于:https://juejin.im/post/5c46e4975188252620583ef5
總結
以上是生活随笔為你收集整理的小码哥iOS学习笔记第八天: block的底层结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【直播资料下载】Python 系列直播—
- 下一篇: 网站漏洞修复公司处理网站被篡改跳转到其他