日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

小码哥iOS学习笔记第八天: block的底层结构

發(fā)布時間:2025/7/14 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小码哥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í)行下述命令行
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m 復(fù)制代碼
  • 將生成的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í)行下述命令行
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m 復(fù)制代碼
  • 將生成的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í)行下述命令行
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m 復(fù)制代碼
  • 將生成的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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。