(一)block的本質,是一個結構體
(二)捕獲變量
第一種:沒有參數,在block中列印,無需捕獲
void (^block)(void) = ^{
NSLog(@"Hello, World!");
};
編譯成c++代碼後(xcrun -sdk phones clang -arch arm64 -rewrite-objc 要編譯的檔案)
// 定義block變量
void (*block)(void) = &__main_block_impl_0(
__main_block_func_0,
&__main_block_desc_0_DATA
);
// 執行block内部的代碼
block->FuncPtr(block);
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
// 構造函數(類似于OC的init方法),傳回結構體對象
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
// 封裝了block執行邏輯的函數
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_c60393_mi_0);
}
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)};
(二)block内有參數傳入(無捕獲)
void (^block)(int, int) = ^(int a, int b){
NSLog(@"Hello, World! - %d %d", a, b);
};
block(10, 20);
在c++中如何展示
void (*block)(int, int) = ((void (*)(int, int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
block->FuncPtr(block, 10, 20);
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
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 a, int b) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_87bc8b_mi_0, a, b);
}
(三)block内部通路了局部變量
( int age = 10,被capture,值傳遞; static int height = 10;被capture,指針傳遞)
void test()
{
int age = 10;
static int height = 10;
block = ^{
// age的值捕獲進來(capture)
NSLog(@"age is %d, height is %d", age, height);
};
age = 20;
height = 20;
}
test();
block();
在c++内部如何顯示
test();
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
void test()
{
int age = 10;
static int height = 10;
block = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, age, &height));
age = 20;
height = 20;
}
struct __test_block_impl_0 {
struct __block_impl impl;
struct __test_block_desc_0* Desc;
int age;
int *height;
__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
static struct __test_block_desc_0 {
size_t reserved;
size_t Block_size;
} __test_block_desc_0_DATA = { 0, sizeof(struct __test_block_impl_0)};
block的類型:NSGlobalBlock NSMallocBlock NSStackBlock
三種
int main(int argc, const char * argv[]) {
@autoreleasepool {
int a = 10;
// 堆:動态配置設定記憶體,需要程式員申請申請,也需要程式員自己管理記憶體
void (^block1)(void) = ^{
NSLog(@"Hello");
};
int age = 10;
void (^block2)(void) = ^{
NSLog(@"Hello - %d", age);
};
NSLog(@"%@ %@ %@", [block1 class], [block2 class], [^{
NSLog(@"%d", age);
} class]);
}
return 0;
}
列印結果如圖
![block1未通路任何變量,為__NSGlobalBlock__ ;block通路了局部變量,本為stack,但在ARC下,自動copy變為malloc
](https://img-blog.csdnimg.cn/20181215221333568.png)
以下為總結:
|通路了auto變量| stack |經過copy變成malloc
|沒有通路auto變量|global|經過copy,無任何改變
| copy stack類型的block 後|變為malloc |再copy後,retaincount+1