一、block能夠捕獲外界變量的原因
在定義Block的時候,外界變量被編譯器轉(zhuǎn)換成了結構體成員變量,并且在調(diào)用Block的時候,這些變量的值會被拷貝到Block的結構體實例中。這樣一來,即使在Block執(zhí)行之后,這些變量的作用域已經(jīng)結束,它們的值也能夠保留下來,并且能夠在Block內(nèi)部繼續(xù)使用。這種特性就是Block所具有的閉包特性,也是它能夠捕獲外界變量的原因。
二、block是什么
block是一種封裝了代碼塊的數(shù)據(jù)類型,可以在C、Objective-C和Swift中使用。它類似于函數(shù)或方法,但具有更靈活的特性,可以嵌套在其他代碼塊中使用,并且能夠捕獲外部變量。block可以作為參數(shù)傳遞給函數(shù)或方法,也可以作為返回值返回。在異步編程、多線程和事件處理等場景中,block被廣泛應用。
block就是一個代碼塊, block是將函數(shù)及其執(zhí)行上下文封裝起來的對象,是一個匿名的函數(shù)對象, block也有isa。既然block內(nèi)部封裝了函數(shù),那么它同樣也有參數(shù)和返回值,本身也可以被作為參數(shù)在方法和函數(shù)間傳遞。
block標準語法:
return_type (^blockName)(var_type) = ^return_type (var_type varName) { // ...};blockName(var);
三、Block底層實現(xiàn)
block的底層實現(xiàn)是結構體,和類的底層實現(xiàn)類似,都有isa指針,可以把block當成是一個對象。下面通過創(chuàng)建一個控制臺程序,來窺探block的底層實現(xiàn)。
block 的內(nèi)存結構圖:
Block_layout結構體成員含義如下:
isa: 指向所屬類的指針,也就是block的類型flags: 標志變量,在實現(xiàn)block的內(nèi)部操作時會用到Reserved: 保留變量invoke: block執(zhí)行時調(diào)用的函數(shù)指針,block內(nèi)部的執(zhí)行代碼都在這個函數(shù)中descriptor: block的詳細描述,包含 copy/dispose 函數(shù),處理block引用外部變量時使用variables: block范圍外的變量,如果block沒有調(diào)用任何外部變量,該變量就不存在Block_descriptor結構體成員含義如下:
reserved: 保留變量size: block的內(nèi)存大小copy: 拷貝block中被 __block 修飾的外部變量dispose: 和 copy 方法配置應用,用來釋放資源具體實現(xiàn)代碼:
enum { BLOCK_REFCOUNT_MASK = (0xffff), BLOCK_NEEDS_FREE = (1 << 24), BLOCK_HAS_COPY_DISPOSE = (1 << 25), BLOCK_HAS_CTOR = (1 << 26), /* Helpers have C++ code. */ BLOCK_IS_GC = (1 << 27), BLOCK_IS_GLOBAL = (1 << 28), BLOCK_HAS_DESCRIPTOR = (1 << 29)};/* Revised new layout. */struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(void *dst, void *src); void (*dispose)(void *);};struct Block_layout { void *isa; int flags; int reserved; void (*invoke)(void *, ...); struct Block_descriptor *descriptor; /* Imported variables. */};
延伸閱讀1:block類型
NSGlobalBlock:沒有訪問auto變量NSStackBlock:訪問了auto變量NSMallocBlock:調(diào)用了copy