前言
最近在總結關于block的東西,可能會寫幾篇關于block的博客,語法那些就不說,這里提供一個語法的入口,我們主要探究block的底層實現、block引用局部變量、block的內存管理,今天先講下block的底層實現。
block實例
#import <Foundation/Foundation.h>
void hello_(){
int i = 2;
int j = 3;
long (^myBlock)(void) = ^long(){
return i*j*10;
};
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
}
return 0;
}
定義hello方法是方便我們等下查看編譯代碼的時候準確定位myBlock的實現。用clang將objected-C 代碼編譯為C++代碼。
控制臺命令:clang -rewrite-objc main.m
我們打開main.cpp文件,定位到以下代碼:
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
這是block基類的定義,所有block都繼承于它,擁有它以下那些屬性:
isa是指向該block的類型的類,也就是我們理解的對象指針;
Flags包含了引用計數;
Reserved:保留變量,我的理解是表示block內部的變量數;
FuncPtr:函數指針,指向具體block實現的函數的調用地址;
struct __hello__block_impl_0 {
struct __block_impl impl;
struct __hello__block_desc_0* Desc;
int i;
int j;
__hello__block_impl_0(void *fp, struct __hello__block_desc_0 *desc, int _i, int _j, int flags=0) : i(_i), j(_j) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
這是myBlock的定義,它的結構體以hello打頭,代表myBlock位于hello函數里,這是block的命名方式。__hello__block_desc_0指的是myBlock的描述。
static long __hello__block_func_0(struct __hello__block_impl_0 *__cself) {
int i = __cself->i; // bound by copy
int j = __cself->j; // bound by copy
return i*j*10;
}
myBlock內函數的具體實現,注意bound by copy,block對外部引用變量做只讀拷貝,還有另外的一種情況,在以后講到關于block引用局部變量的時候會說。
static struct __hello__block_desc_0 {
size_t reserved;
size_t Block_size;
} __hello__block_desc_0_DATA = { 0, sizeof(struct __hello__block_impl_0)};
這是myBlock的具體描述
void hello_(){
int i = 2;
int j = 3;
long (*myBlock)(void) = ((long (*)())&__hello__block_impl_0((void *)__hello__block_func_0, &__hello__block_desc_0_DATA, i, j));
}
myBlock實例變量的定義
做下小小總結
block是對象;
編譯器會根據block捕獲的局部變量,生成具體的結構體定義。block內部的代碼將會提取出來,成為一個單獨的C函數(eg:__hello__block_func_0)。創(chuàng)建block時,實際就是在方法中聲明一個struct,并且初始化該struct的成員。而執(zhí)行block時,就是調用那個單獨的C函數,并把該struct指針傳遞過去;
block中包含了被引用的局部變量(由struct持有),也包含了控制成分的代碼塊(由函數指針持有),符合閉包(closure)的概念。