精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

iOS 開發—探秘 Block 原理

移動開發 iOS
很多block原理性的文章都比較老,里面講的一些知識已經過時,這里用新版的iOS SDK再梳理一遍block原理,也是和大家一起對已有知識做一次復習。

1.概述

在iOS開發中,block大家用的都很熟悉了,是iOS開發中閉包的一種實現方式,可以對一段代碼邏輯進行封裝,使其可以像數據一樣被傳遞、存儲、調用,并且可以保存相關的上下文狀態。

很多block原理性的文章都比較老,里面講的一些知識已經過時,這里用新版的iOS SDK再梳理一遍block原理,也是和大家一起對已有知識做一次復習。

2.內存布局

block本質上可以理解為結構體,對于結構體的內存布局,先用一張圖來表示一下,圖中字段順序按照布局的先后順序:

  • isa:block也有isa,從內存結構上也屬于對象,isa指向的是block的類對象,類對象例如__NSMallocBlock__,后續文章會講到;
  • flags:用于存儲一些標志位信息,例如是否捕獲外部變量;
  • reserved:系統保留字段,后續可能會用于一些編譯優化標志位,或者存儲一些臨時變量的處理;
  • invoke:函數指針,指向了block要執行的函數地址,也就是block代碼塊對應的函數地址;
  • descriptor(現在叫desc):指向block_desc_0,包含block大小、捕獲的外部變量布局信息、增加引用計數和銷毀的相關函數指針;
  • variables:block捕獲的外部變量。

圖片圖片

3.類型

由于block也是對象,可以通過class方法獲取到其類型,也就是類對象。block有下面三種類型:

  • __NSGlobalBlock__,沒有訪問auto變量的block,訪問static變量是沒問題的。這種類型的變量并沒有什么意義,如果不需要用到auto變量,寫成方法就可以滿足需求;
  • __NSStackBlock__,在MRC環境下,訪問了auto變量,會默認被放在棧區。需要手動copy到堆區,ARC環境下會在訪問auto變量后,會自動拷貝到堆區;
  • __NSMallocBlock__,由開發者自己管理內存,不會由系統來釋放。

block的分配主要是在三個區域,堆區、棧區、全局區,全局區的數據存儲在數據段。

block在不同的場景會存在不同的內存區域中,在MRC中創建一個block首先是在__NSStackBlock__內存中的,然后我們使用copy方法將block拷貝到__NSMallocBlock__內存中進行內存管理。后來在ARC中系統已經幫我們做好了copy的操作,創建的block會自動copy到__NSMallocBlock__內存中,堆區的block也有引用計數的概念。如果這個block中沒有用到任何外部參數,系統會將這個block存放在__NSGlobalBlock__內存中。

圖片圖片

并且block也有繼承關系,以下面TestBlock的實例來說,其父類是__NSGlobalBlock__,所有block的父類是NSBlock,并且NSBlock繼承自NSObject類。在更早一些的iOS系統中,__NSGlobalBlock__和NSBlock之間,還會有一層__NSGlobalBlock的關系(后面沒有下劃線)。

圖片圖片

4.轉換C++

下面,我們通過clang命令將block轉為結構體,來分析下其具體實現。雖然這并不是最終運行在iOS系統上的代碼,其等于一種中間表現形式,后續編譯鏈接優化才會形成運行在手機上的ipa包,但對于我們了解block的實現原理有很大幫助。

4.1轉換命令

xcrun是Xcode用于查找和執行相關命令行的工具集,可以更好的執行clang命令,減少報錯。

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc [源文件路徑] -o [目標文件路徑]

clang命令有下面這些關鍵參數:

  • -fobjc-arc:如果項目是ARC或者ARC和MRC混編的環境,需要通過此參數修飾,表示按ARC的方式進行轉換,如果不需要ARC環境可以忽略;
  • -x objective-c++:此參數上面沒用,如果包含Objective++源文件的時候,需要用到此參數,以確保clang可以區分OC和C++代碼;
  • -rewrite-objc:告訴clang以C++的方式重寫出來,包含的上層代碼,clang會以底層代碼的方式進行展現;
  • [目標文件路徑]:非必傳參數,不傳的話默認在當前目錄生成一個同名的cpp文件,例如main.m對應main.cpp。

4.2轉換示例

下面在main.m中實現了一個很簡單的block,并且沒有捕獲任何外部變量,通過clang命令查看C++代碼,觀察block的具體實現原理。

圖片圖片

轉換后將C++源文件拉到最下面,可以看到main函數以及TestBlock的實現,main函數中有很多轉義代碼,刪掉后梳理邏輯會更清晰。

圖片圖片

5.結構體

5.1基礎結構

轉換后的代碼看著比較復雜,但我們只看關鍵信息,__main_block_impl_0構造函數也可以去掉,整理后就是下面三個結構體。在不包含外部變量和__block的前提下,block結構體各個字段就這么簡單,關鍵就是isa、Block_size、FuncPtr這三個。

圖片圖片

我們也可以打印block結構體相關字段,但由于block的結構體并沒有聲明在某個.h文件中,所以需要我們講clang轉換后的結構體粘到對應的文件中,做顯示聲明。隨后用__bridge的方式,將block對象橋接為自己聲明的結構體,即可打印對應字段。

圖片圖片

結構體中impl.FuncPtr存儲的就是回調函數地址,從地址可以看出是一個虛擬地址,block結構體都存儲在堆區。

圖片圖片

5.2調用部分

看完block結構體的定義,我們來到main函數中,看block的實現和調用轉換后是什么樣的。將main函數中block相關的轉換都去掉,結果如紅圈部分。本質上就是兩步,第一步是調用__main_block_impl_0的結構體構造函數,第二步是調用結構體的函數指針。

圖片圖片

第一行main函數中調用的構造方法,是__main_block_impl_0結構體聲明的C++構造函數,因為我們創建的是一個最簡單block,可以看到block的存儲區域是在stack棧區的。即main函數調用完,block生命周期就會結束。

圖片圖片

__main_block_impl_0構造函數有兩個參數,第一個紅圈部分就是傳入函數指針地址,函數對應的就是block內部的實現代碼。第二個參數是__main_block_desc_0_DATA結構體,其定義為__main_block_desc_0,并且默認實現第一個參數傳0,第二個參數是block結構體的大小,結構體為__main_block_impl_0 block自身的結構體大小。第三個參數有默認值,可以不傳。

圖片圖片

__main_block_desc_0結構體是一種緊湊型的寫法,在聲明__main_block_desc_0結構體后,緊接著聲明了一個名為__main_block_desc_0_DATA的變量,變量類型為靜態變量,并且實現了初始化相關代碼。

圖片圖片

在執行block的代碼位置,可以看到并不是block->impl.FuncPtr的方式調用,而是直接block->FuncPtr的方式調用,中間少了一步。

嚴謹些來說應該加上impl,但不加也不會出問題。這是因為,如果看未刪除轉換代碼的原始clang代碼,可以看到block是被轉換為__block_impl的,也就是說被當做__block_impl看待的。如果再結合__main_block_impl_0的結構體定義來看,__block_impl在成員變量的第一位,所以訪問FuncPtr是沒有問題的,只要不訪問Desc就是可以的。

6.外部變量

6.1值類型

如果在block的調用中加一個外部變量,那結構體將會是怎樣的?

圖片圖片

通過clang命令可以可以看到,轉換后的__main_block_impl_0中增加了一個同名字段,這很簡單沒必要過多解釋。在__main_block_impl_0構造函數中傳入,通過冒號后的初始化列表對value參數進行初始化。

圖片圖片

后面傳參和使用,就都是結構體賦值和取值邏輯,很簡單。

圖片圖片

6.2值傳遞

下面這種寫法,在block的使用中很容易踩坑。在block中使用value參數,并且打印value參數,發現結果為1,而不是2。

圖片圖片

通過C++源碼我們可以看到,這是因為如果block引用的外部變量是值類型,會采取直接復制值的方式,而不是指針引用。

圖片圖片

想解決這個問題也很簡單,通過__block修飾一下值類型,即可實現block內value的值和外部value參數統一。

圖片圖片

6.3靜態變量

我們看一下,如果捕獲的是一個static修飾的靜態變量,其結構體會是什么實現。

圖片圖片

轉換為C++代碼后,可以看到原來的值傳遞變成了地址傳遞,__main_block_impl_0中value的引用是指針引用,在main函數中將value的地址傳入。如果被static修飾的本身就是一個對象,對象是通過指針引用的,在block的結構體中就是兩個星號引用。也就是NSObject **obj。

圖片圖片

正是由于靜態變量地址傳遞的實現,在block內可以對靜態變量直接進行更改,而無需用__block進行修飾。

圖片圖片

6.4全局變量

如果把value改為全局變量,結構體會有什么變化呢?

圖片圖片

因為全局變量的作用域很大,所以并不需要block進行單獨持有即可訪問,結構體并不會新增字段。

圖片圖片

6.5對象類型變量

如果block中引用的是對象,而不是基礎數據類型,結構體會是什么定義呢?

圖片圖片

執行clang命令,執行完成后結構體是下圖的,下面代碼去掉了轉換,以及整理過代碼。可以看到多了兩個函數指針,__main_block_copy_0和__main_block_dispose_0。

以copy的實現__main_block_copy_0為例,執行后會調用Block_object_assign的實現,在實現中系統會根據person的引用方式,__strong、__weak、__unsafe_unretained,是強引用還是弱引用,調用對應的內存管理方法。

__main_block_dispose_0函數在block從堆區移除的時候被調用,調用dispose時會調用實現Block_object_dispose函數,函數中會根據person的引用方式,進行對應的減少引用計數或釋放操作。

copy和dispose兩個函數都有一個3的參數,這個參數是一個標志位,表示外部變量類型。這里是BLOCK_FIELD_IS_OBJECT表示一個對象類型,也有BLOCK_FIELD_IS_WEAK表示weak引用的變量,BLOCK_FIELD_IS_BLOCK表示block類型的變量等。

圖片圖片


責任編輯:武曉燕 來源: 搜狐技術產品
相關推薦

2013-06-04 15:41:31

iOS開發移動開發block

2009-06-15 15:57:21

Spring工作原理

2017-03-07 09:45:43

iOSBlock開發

2023-06-07 15:25:19

Kafka版本日志

2025-02-08 08:10:00

2013-07-19 12:52:50

iOS中BlockiOS開發學習

2024-02-27 22:31:00

Feign動態代理核心

2023-02-22 07:04:05

自動機原理優化實踐

2011-08-08 18:11:45

IOS 4Block UIActionShe

2009-11-04 15:54:20

Portlet入門企業門戶

2010-08-09 08:48:46

File APIWeb

2009-11-06 16:10:54

ClosureJavaScript開Google

2010-02-26 17:54:54

python

2010-08-27 10:41:41

iPhone核心應用程序

2014-03-07 13:23:23

百度面試iOS

2009-08-25 13:48:01

Java EE架構企業級應用

2013-07-19 14:00:13

iOS中BlockiOS開發學習

2013-07-19 14:35:59

iOS中BlockiOS開發學習

2011-06-28 10:42:38

Windows 8開發部門DevX

2013-04-17 10:06:55

Google GlasMirror API
點贊
收藏

51CTO技術棧公眾號

91久久嫩草影院一区二区| 在线看不卡av| 久久亚洲精品欧美| 中文字幕在线观看1| 成人在线超碰| 欧美性xxxxxxxxx| 中文字幕黄色大片| 偷拍精品一区二区三区| 亚洲国产三级| 日韩电影中文字幕在线观看| 草草视频在线免费观看| 国产农村妇女毛片精品| 天天影视欧美综合在线观看| 精品视频1区2区| 欧美一级免费播放| 色三级在线观看| 99精品国产91久久久久久| 久久久久久久久久av| 又色又爽又黄18网站| 欧美1—12sexvideos| 粉嫩aⅴ一区二区三区四区 | 国产免费无码一区二区| 日本高清成人vr专区| 国产福利91精品| 国产精品999999| 日韩三级视频在线播放| 日韩欧美美女在线观看| 欧美性猛交99久久久久99按摩| 精品午夜一区二区三区| 日本午夜视频在线观看| 伊人春色精品| 亚洲国产精品久久久| 欧美三级一级片| 蜜乳av一区| 亚洲视频你懂的| 亚洲国产欧美不卡在线观看| 国产精品久久免费| 蜜臀av性久久久久蜜臀aⅴ流畅| 久久久精品国产| av电影在线不卡| 亚洲精品亚洲人成在线| 欧美日韩国产小视频在线观看| 日本特级黄色大片| h视频网站在线观看| 国产精品白丝jk黑袜喷水| 97在线观看免费高清| 亚洲精品国产熟女久久久| 影视一区二区三区| 一本大道久久a久久精品综合| 亚洲一区免费看| 麻豆影视在线| 久久精品欧美日韩| 秋霞在线观看一区二区三区| 国产毛片在线视频| 国产呦萝稀缺另类资源| 成人精品视频在线播放| 污片在线免费看| 亚洲成人激情小说| 综合毛片免费视频| 天天操天天色综合| 精品久久久久久久久久中文字幕| 国产福利电影在线| 国产午夜精品久久| 亚洲在线视频观看| 久久美女免费视频| 精品99在线| 久久久xxx| 久久久国产精彩视频美女艺术照福利| 免费看日本黄色片| 日韩免费高清| 久久久精品在线| 久久久久成人精品无码| 偷拍自拍亚洲色图| 亚洲开心激情网| 2019男人天堂| 亚洲国产一成人久久精品| 亚洲男人天堂视频| 中国女人特级毛片| 99久久婷婷国产综合精品电影√| 亚洲欧洲在线免费| 亚洲最大成人综合网| 亚洲人挤奶视频| 色妞久久福利网| 亚洲成人生活片| 91影院成人| 久久久久成人网| 午夜精品免费观看| 国产一区不卡精品| 麻豆一区区三区四区产品精品蜜桃| 国产a级免费视频| 成人一区二区三区中文字幕| 666精品在线| 台湾av在线二三区观看| 99视频超级精品| 五月婷婷综合色| 欧美伦理免费在线| 欧美性色19p| 男生和女生一起差差差视频| 日韩一级视频| 亚洲福利视频久久| 青青青视频在线免费观看| 精品一区二区三区中文字幕老牛 | 婷婷激情五月网| 青娱乐精品视频| 岛国一区二区三区高清视频| 亚洲AV无码国产精品午夜字幕 | 91丨九色丨蝌蚪| 精品网站aaa| 久久综合久中文字幕青草| 四虎永久免费在线| 鲁大师成人一区二区三区| 青青草精品毛片| www.久久精品.com| 国产欧美日韩不卡免费| 一区二区不卡在线| 美女网站在线看| 日韩一级大片在线观看| 国产精品二区视频| 成人在线免费观看91| 久久久精品视频成人| 欧美日韩成人免费观看| 在线观看一区视频| 成人妇女免费播放久久久| 国产精品区在线观看| 国产主播一区二区| 日韩影院一区| 校园春色亚洲色图| 亚洲精品mp4| 国产一级淫片免费| 国产成人亚洲综合a∨婷婷图片| 国产精品久久久久久久小唯西川 | 亚洲欧美激情小说另类| 亚洲蜜桃av| 国产v日韩v欧美v| 欧美精品成人一区二区三区四区| 污视频在线观看免费网站| 97品白浆高清久久久久久| 亚洲精品第一国产综合精品| 国产免费看av| 国产欧美日韩一级| 国产欧美最新羞羞视频在线观看| 精品国产黄色片| 日韩毛片在线免费观看| 免费看一级大黄情大片| 草民电影神马电影一区二区| 日韩一区二区三区av| 国产白嫩美女无套久久| 欧美r级电影| 国产精品视频中文字幕91| 一起操在线视频| 国产精品美女久久久久av爽| 99伊人成综合| 国产日韩欧美一区二区三区四区| 日本高清中文字幕二区在线| 国产精品久久毛片| 亚洲老女人av| 欧美1级片网站| 91夜夜未满十八勿入爽爽影院| 婷婷伊人综合中文字幕| 综合久久久久久久| 欧洲美女亚洲激情| 欧美精品一区二区三区久久久竹菊| 日本aⅴ大伊香蕉精品视频| 91精品国自产| 亚洲精品国产a| 日韩女优在线视频| 一本不卡影院| 日韩欧美精品一区二区三区经典| 9999在线视频| 日韩大陆欧美高清视频区| 在线看的片片片免费| 久久综合九色| 亚洲一区二区三区免费观看| 在线观看欧美日韩电影| 日韩精品一区二区三区在线播放 | 超碰在线资源站| 国产精品啊v在线| 亚洲一区二区三区四区在线观看| 国产尤物91| 三上悠亚激情av一区二区三区 | 欧洲熟妇的性久久久久久| 日韩成人精品一区| 91成人免费观看| 麻豆免费在线| 色妞一区二区三区| 男人天堂av网| 欧美性生活大片视频| 少妇特黄一区二区三区| 伊人蜜桃色噜噜激情综合| 国产在线高清精品| 久久五月精品中文字幕| 日韩无一区二区| 香蕉影院在线观看| 成人欧美一区二区三区小说| 日韩精品视频一二三| 日韩国产在线| 翡翠波斯猫1977年美国| 后进极品白嫩翘臀在线播放| 欧美日韩色综合| 国产午夜福利精品| 国产精品嫩草久久久久| www.久久久精品| 亚洲精品人人| 日本一级淫片演员| 国产成人影院| 国产精品678| 激情av在线播放| 中文字幕日韩欧美| 日韩欧美亚洲系列| 日韩午夜av一区| 中文字幕欧美人妻精品一区蜜臀| 国产亚洲精品7777| 美国黄色一级视频| 麻豆精品在线播放| 久久精品免费一区二区| 日韩欧洲国产| 欧美日韩一区二区三区| 国产草草浮力影院| 久色婷婷小香蕉久久| 在线成人av电影| 日韩精选在线| aa日韩免费精品视频一| h片在线免费| 亚洲欧美国产va在线影院| 亚洲欧美综合另类| 亚洲黄色小视频| 日韩在线视频免费看| 韩国三级在线一区| 噼里啪啦国语在线观看免费版高清版| 欧美天天视频| 一道本在线观看视频| 成人免费在线电影网| 日韩av电影免费观看高清| 1pondo在线播放免费| 欧美va在线播放| 国产精品日韩无码| 欧美日韩国产综合久久 | 色噜噜狠狠狠综合曰曰曰| 国产精品欧美激情在线| 午夜伦理一区二区| 久久久夜色精品| 亚洲激情五月婷婷| 老女人性淫交视频| 亚洲精品视频在线| 亚洲 欧美 变态 另类 综合| 成人午夜av在线| 欧美极品jizzhd欧美仙踪林| 免费高清在线一区| 另类小说第一页| 青青草国产成人av片免费| 日韩一区二区高清视频| 日本一区二区在线看| 国产精品乱码视频| 国产精品白浆| 精品婷婷色一区二区三区蜜桃| 成人免费91| 亚洲综合一区二区不卡| av在线日韩| 国产精品久久视频| 2020国产精品小视频| 欧美一级高清免费| 日韩成人高清| 国产日韩精品一区二区| 粉嫩一区二区| 国产精品日韩欧美综合| 秋霞伦理一区| 国产91露脸中文字幕在线| 3344国产永久在线观看视频| 精品国产欧美一区二区三区成人 | 韩日精品视频一区| 欧美福利视频在线| 国产av一区二区三区| 日本精品一区二区三区高清| 国产亚洲小视频| 欧美日韩国产一区中文午夜| 放荡的美妇在线播放| 久久精品无码一区二区三区| 蜜臀aⅴ国产精品久久久国产老师| 男女男精品视频| 手机精品视频在线| 99久久99精品久久久久久| 中日韩av在线播放| 国产成人av一区二区三区在线| www.久久久精品| 国产不卡免费视频| 好吊视频在线观看| 亚洲丝袜自拍清纯另类| 天堂av网手机版| 一级女性全黄久久生活片免费| 国产成人自拍网站| 精品国产乱码久久久久久天美| 久久亚洲AV无码| 日本高清视频一区二区| 国产性生活视频| 3atv一区二区三区| 视频福利在线| 欧美成人精品xxx| 伊人久久综合一区二区| 欧美一级bbbbb性bbbb喷潮片| 亚洲日本天堂| 51午夜精品| 91亚洲国产成人久久精品| 伊人狠狠色丁香综合尤物| 日韩精品影视| jizzjizz国产精品喷水| 可以看av的网站久久看| 中文字幕一区二区三区四区在线视频| 国产成都精品91一区二区三| 岛国精品一区二区三区| 99久久er热在这里只有精品66| 特大黑人巨人吊xxxx| 久久久久国产成人精品亚洲午夜| 国产精品亚洲无码| 亚洲愉拍自拍另类高清精品| 福利一区二区三区四区| 欧美小视频在线观看| 91丨九色丨海角社区| 欧美乱妇23p| www.中文字幕久久久| www.欧美精品| 影视一区二区三区| 女人一区二区三区| 一区二区国产在线观看| 凹凸日日摸日日碰夜夜爽1| 七七婷婷婷婷精品国产| 欧美国产在线一区| 国产精品久久久久久久久晋中| 免费无遮挡无码永久在线观看视频 | 一个色综合网站| 国产又爽又黄又嫩又猛又粗| 精品少妇一区二区三区在线播放| 天天综合天天综合| 久久久久亚洲精品| 日韩高清在线观看一区二区| 国产在线精品日韩| 欧美日韩国内| 中文av字幕在线观看| 成人免费高清视频| 永久免费看黄网站| 欧美一级黄色大片| a毛片在线播放| 91九色视频在线观看| 自拍亚洲一区| 丰满爆乳一区二区三区| 麻豆精品在线视频| 欧美图区在线视频| 激情福利在线| 国产福利视频一区| 色视频免费在线观看| 国产欧美日韩在线视频| 老熟妻内射精品一区| 偷拍与自拍一区| 亚洲AV成人无码一二三区在线| 综合av色偷偷网| 国产精品66| 先锋影音男人资源| 国产不卡视频在线播放| 久久久久久久毛片| 欧美亚洲国产一区二区三区va| 丰满熟妇乱又伦| 国内精品400部情侣激情| 日韩深夜福利网站| 国产经典久久久| 成人免费视频网站在线观看| 婷婷综合在线视频| 91.com视频| 五月花成人网| 精品一卡二卡三卡四卡日本乱码 | 日韩免费黄色av| 波多野结衣一区| 91精品国产三级| 亚洲无线码一区二区三区| 国产精品一区二区免费视频| 亚洲人成五月天| 亚洲欧美在线综合| 69sex久久精品国产麻豆| 丁香六月久久综合狠狠色| 日本一级二级视频| 日韩成人在线观看| 国产精品诱惑| 国产美女主播在线| 国产日韩欧美制服另类| 日韩精品一区不卡| 久久影院中文字幕| 老司机aⅴ在线精品导航| 农民人伦一区二区三区| av一区二区三区四区| 国产精品111| 伊人伊成久久人综合网站| 欧美一级二级视频| 免费的av在线| 久久女同精品一区二区| 欧美一区二区三区不卡视频| 日韩精品中文字幕有码专区| 漫画在线观看av| 97超碰免费观看| 国产亚洲一区二区三区在线观看| 日韩精品一区二区亚洲av观看| 亚洲人成电影在线播放| 欧美三区四区|