赞
踩
Blocks是C语言的扩充功能:带有自动变量(局部变量)的匿名函数。
“带有自动变量”在Blocks中表现为“截取自动变量"
“匿名函数”就是“不带名称的函数”
块,封装了函数调用及调用环境的OC对象
// 1.
@property (nonatomic, copy) void(^myBlock1)(void);
// 2.BlockType:类型别名
typedef void(^BlockType)(void);
@property (nonatomic, copy) BlockType myBlock2;
// 3.
// 返回值类型(^block变量名)(参数1类型,参数2类型,...)
void(^block)(void);
// ^返回值类型(参数1,参数2,...){}; // 1.无返回值,无参数 void(^block1)(void) = ^{ }; // 2.无返回值,有参数 void(^block2)(int) = ^(int a){ }; // 3.有返回值,无参数(不管有没有返回值,定义的返回值类型都可以省略) int(^block3)(void) = ^int{ return 3; }; // 以上Block的定义也可以这样写: int(^block4)(void) = ^{ return 3; }; // 4.有返回值,有参数 int(^block5)(int) = ^int(int a){ return 3 * a; };
// 1.无返回值,无参数
block1();
// 2.有返回值,有参数
int a = block5(2);
通过Clang将以下的OC代码转化为C++代码
// Clang
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m
//main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
void(^block)(void) = ^{
NSLog(@"我是 block");
};
block();
}
return 0;
}
转化为C++代码
//参数结构体 struct __main_block_impl_0 { struct __block_impl impl;// block 结构体 struct __main_block_desc_0* Desc;// block 的描述对象 /* block 的构造函数 ** 返回值:__main_block_impl_0 结构体 ** 参数一:__main_block_func_0 结构体 ** 参数二:__main_block_desc_0 结构体的地址 ** 参数三:flags 标识位 */ __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock;// &_NSConcreteStackBlock 表示存储在栈上 impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; //block 结构体 struct __block_impl { void *isa;//block 的类型 int Flags; int Reserved; void *FuncPtr;// block的执行函数指针,指向__main_block_func_0 }; //封装了 block 中的代码 //参数是__main_block_impl_0结构体的指针 static void __main_block_func_0(struct __main_block_impl_0 *__cself) { NSLog((NSString *)&__NSConstantStringImpl__var_folders_yx_7jg_wdg128v45l4cn_1g265h0000gn_T_main_03dcda_mi_0); } static struct __main_block_desc_0 { size_t reserved; size_t Block_size;// block 所占的内存空间 } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; /* ** void(^block)(void) = ^{ NSLog(@"调用了block"); }; ** 定义block的本质: ** 调用__main_block_impl_0()构造函数 ** 并且给它传了两个参数 __main_block_func_0 和 &__main_block_desc_0_DATA ** __main_block_func_0 封装了block里的代码 ** 拿到函数的返回值,再取返回值的地址 &__main_block_impl_0, ** 把这个地址赋值给 block */ void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)); /* ** block(); ** 调用block的本质: ** 通过 __main_block_impl_0 中的 __block_impl 中的 FuncPtr 拿到函数地址,直接调用 */ ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); } return 0; }
将以下 OC 代码转换为 C++ 代码,并贴出部分变动代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
int age = 10;
void(^block)(void) = ^{
NSLog(@"%d",age);
};
block();
}
return 0;
}
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; int age;//生成的变量 __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { int age = __cself->age; // bound by copy NSLog((NSString *)&__NSConstantStringImpl__var_folders_yx_7jg_wdg128v45l4cn_1g265h0000gn_T_main_40c716_mi_0,age); }
可以看出:
由于传递方式为值传递,所以我们在block外部修饰age变量时,不会影响到block中的age变量
总的来说,所谓“截获自动变量”意味着在执行Block语法时,Block语法表达式所用的自动变量被保存到Block的结构体实例中(即Block自身)中
将以下OC代码转化为C++代码,并贴出部分变动代码
static int age = 10;
void(^block)(void) = ^{
NSLog(@"%d",age);
};
age = 20;
block();
// 20
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; int *age; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_age, int flags=0) : age(_age) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { int *age = __cself->age; // bound by copy NSLog((NSString *)&__NSConstantStringImpl__var_folders_yx_7jg_wdg128v45l4cn_1g265h0000gn_T_main_cb7943_mi_0,(*age)); }
可以看出:
由于传递方式是指针传递,所以修改局部变量age时,age的值会随之变化
将以下OC代码转化为C++代码,并贴出部分变动代码
int height = 10;
static int age = 20;
int main(int argc, const char * argv[]) {
@autoreleasepool {
void(^block)(void) = ^{
NSLog(@"%d,%d",height,age);
};
block();
}
return 0;
}
int height = 10; static int age = 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; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { NSLog((NSString *)&__NSConstantStringImpl__var_folders_yx_7jg_wdg128v45l4cn_1g265h0000gn_T_main_7a340f_mi_0,height,age); }
可以看出:
虽然block语法的匿名函数部分简单地变换为了C语言函数,但从这个变换的函数中访问静态全局变量/全局变量并没有任何改变,可直接使用。
但是静态变量的情况下,转换后的函数原本就设置在含有Block语法的函数外,所以无法从变量作用域访问
为什么局部变量需要捕获,而全局变量不用呢?
默认情况下block是不能修改外面的auto变量,解决办法?
struct __Block_byref_age_0
(byref
:按地址传递));将以下 OC 代码转换为 C++ 代码,并贴出部分变动代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
__block int age = 10;
void(^block)(void) = ^{
age = 20;
NSLog(@"block-%d",age);
};
block();
NSLog(@"%d",age);
}
return 0;
}
struct __Block_byref_age_0 { void *__isa; __Block_byref_age_0 *__forwarding;//持有指向该实例自身的指针 int __flags; int __size; int age; }; struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __Block_byref_age_0 *age; // by ref __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { __Block_byref_age_0 *age = __cself->age; // bound by ref (age->__forwarding->age) = 20; NSLog((NSString *)&__NSConstantStringImpl__var_folders_yx_7jg_wdg128v45l4cn_1g265h0000gn_T_main_75529b_mi_0,(age->__forwarding->age)); } static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->age, (void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);} static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}
可以看出:
__Block_byref_age_0
结构体对象__main_block_func_0
结构体实例中( __Block_byref_age_0
)类型的age指针,找到 __Block_byref_age_0
结构体的对象, __Block_byref_age_0
结构体对象持有指向实例本身的__forwarding指针,通过成员变量_forwarding访问 __Block_byref_age_0
结构体里的age变量,并将值改为20;Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。