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