定義
void (^名稱)(參數(shù)) = ^{
};
使用
名稱();
參考示例
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
int num = 1;
void (^block)(void) = ^{
NSLog(@"打印了 num = %d",num);
NSLog(@"這個是 block");
};
block();
}
return 0;
}
原理解析
首先我們將上面的代碼生成 cpp 文件看一下上面的代碼會將我們的內(nèi)容編譯成什么樣子
編譯命令:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
最終生成內(nèi)容如下
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_dv_nb1mrprn3kj3cnk3tts4918w0000gn_T_main_f590b1_mi_0);
int num = 1;
void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, num));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
關鍵結構體有下面內(nèi)容
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int num;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _num, int flags=0) : num(_num) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int num = __cself->num; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_dv_nb1mrprn3kj3cnk3tts4918w0000gn_T_main_f590b1_mi_1,num);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_dv_nb1mrprn3kj3cnk3tts4918w0000gn_T_main_f590b1_mi_2);
}
可以發(fā)現(xiàn)我們最后的 block 定義其實是生成了一個結構體,并通過結構體的構造函數(shù)傳遞了三個參數(shù)。
&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, num)
參數(shù)一:__main_block_func_0 則是我們實際執(zhí)行的代碼
參數(shù)二: __main_block_desc_0_DATA 是 block 的信息記錄,Block_size 記錄了 block 的大小。
參數(shù)三:num 則是我們訪問的外部變量,賦值給了 block 內(nèi)的變量 num
而且通過觀察 __main_block_impl_0,我們可以發(fā)現(xiàn)此處也是生成了 isa 指針的,所以我們可以確認我們的 block 是一個對象。并且在構造函數(shù)中將傳入的代碼執(zhí)行地址傳遞給了 impl 的 funcPtr, 在下面我們調用 block() 的時候實際也就是調用的 (impl->funcPtr)(num)