什么是Block?
Block 又称为“块” 或 “代码块”,作用是用来保存代码,保存在其内部的代码块 如果Block不被调用 这段代码就不会执行
在OC中Block的基本格式是这样的
返回值类型 (^block名) (参数类型 和 数量) = ^(形参 和 数量){
//code
};
Block的本质上也是一个OC对象 它内部也有个isa指针
Block是封装了函数调用以及函数调用环境(比如参数和返回值)的OC对象
Block是封装了函数及其上下文的OC对象
1、写一个简单的block:
@autoreleasepool {
appDelegateClassName = NSStringFromClass([AppDelegate class]);
MyBlock myBlock = ^{
};
NSLog(@"myBlock:%@",myBlock);//myBlock:<__NSGlobalBlock__: 0x10bfde038>
myBlock();
}
转成底层代码
typedef void(*MyBlock)(void);
//Block的本质
struct __block_impl {
void *isa;//isa指针(Block的类型-->指向Class)
int Flags;
int Reserved;
void *FuncPtr;//封装代码块的地址
};
struct __test_block_impl_0 {
struct __block_impl impl;
struct __test_block_desc_0* Desc;
// 构造函数(类似于OC的init方法),返回结构体对象
__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {
}
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)};
void test(){
MyBlock myBlock = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
2、block内部捕获变量
int a_q = 10;//全局变量
static int b_q = 10;//全局静态变量
typedef void(^MyBlock)(void);
void test(){
int a = 10;//局部变量
static int b = 10;//局部静态变量
MyBlock myBlock = ^{
NSLog(@"a=%d", a);//a=10
NSLog(@"b=%d", b);//b=20
NSLog(@"a_q=%d", a_q);//a_q=20
NSLog(@"b_q=%d", b_q);//b_q=20
};
a = 20;
b = 20;
a_q = 20;
b_q = 20;
myBlock();
}
转成底层代码
typedef void(*MyBlock)(void);
//Block的本质
struct __block_impl {
void *isa;//isa指针(Block的类型-->指向Class)
int Flags;
int Reserved;
void *FuncPtr;//封装代码块的地址
};
int a_q = 10;
static int b_q = 10;
typedef void(*MyBlock)(void);
struct __test_block_impl_0 {
struct __block_impl impl;
struct __test_block_desc_0* Desc;
int a;
int *b;
__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _a, int *_b, int flags=0) : a(_a), b(_b) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {
int a = __cself->a; // bound by copy
int *b = __cself->b; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_0, a);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_1, (*b));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_2, a_q);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_3, b_q);
}
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)};
void test(){
int a = 10;
static int b = 10;
MyBlock myBlock = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, a, &b));
a = 20;
b = 20;
a_q = 20;
b_q = 20;
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
分析:
1、局部变量a:可以看到我们Block内部有一个(int _a)变量,局部变量a直接传值给_a;(在局部变量中 auto局部变量出了作用域就会销毁 为了避免执行block时 变量不存在 所以auto变量在Block内部被直接赋值为当前值)
2、局部静态变量b:可以看到我们Block内部有一个(int _b)变量,局部静态变量b把b(指针)传给*_b;(static变量一直存在于内存中不必有此担忧,所以存储的是变量指针,可以随时取出最新值。)
3、全局变量a_q和全局静态变量b_q:Block内部没有生成对应的变量(如果是全局变量 Block使用时不用捕获 直接访问 所以得到的也全部都是最新值。)
总结:局部变量之所以需要捕获 因为我们是跨函数使用的 声明和使用不是在一个作用域内
注意:self这个变量也是局部变量 也会被block捕获,因为在OC中所有的方法编译后都是自带两个参数 一个是实例对象 一个是SEL _cmd
所以Block中如果用到self,self也会被捕获。且Block内部的self属性 指向我们传进去的self
所以 我们也能理解为什么会造成循环引用了吧。
self捕获
int a_q = 10;
static int b_q = 10;
typedef void(^MyBlock)(void);
- (void)test{
int a = 10;
static int b = 10;
MyBlock myBlock = ^{
NSLog(@"a=%d", a);//a=10
NSLog(@"b=%d", b);//b=20
NSLog(@"a_q=%d", a_q);//a_q=20
NSLog(@"b_q=%d", b_q);//b_q=20
NSLog(@"%@",self);
};
a = 20;
b = 20;
a_q = 20;
b_q = 20;
myBlock();
}
转成底层代码
int a_q = 10;
static int b_q = 10;
typedef void(*MyBlock)(void);
struct __ViewController__test_block_impl_0 {
struct __block_impl impl;
struct __ViewController__test_block_desc_0* Desc;
int a;
int *b;
ViewController *self;
__ViewController__test_block_impl_0(void *fp, struct __ViewController__test_block_desc_0 *desc, int _a, int *_b, ViewController *_self, int flags=0) : a(_a), b(_b), self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __ViewController__test_block_func_0(struct __ViewController__test_block_impl_0 *__cself) {
int a = __cself->a; // bound by copy
int *b = __cself->b; // bound by copy
ViewController *self = __cself->self; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_0, a);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_1, (*b));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_2, a_q);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_3, b_q);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_4,self);
}
static void __ViewController__test_block_copy_0(struct __ViewController__test_block_impl_0*dst, struct __ViewController__test_block_impl_0*src) {_Block_object_assign((void*)&dst->self, (void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __ViewController__test_block_dispose_0(struct __ViewController__test_block_impl_0*src) {_Block_object_dispose((void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __ViewController__test_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __ViewController__test_block_impl_0*, struct __ViewController__test_block_impl_0*);
void (*dispose)(struct __ViewController__test_block_impl_0*);
} __ViewController__test_block_desc_0_DATA = { 0, sizeof(struct __ViewController__test_block_impl_0), __ViewController__test_block_copy_0, __ViewController__test_block_dispose_0};
static void _I_ViewController_test(ViewController * self, SEL _cmd) {
int a = 10;
static int b = 10;
MyBlock myBlock = ((void (*)())&__ViewController__test_block_impl_0((void *)__ViewController__test_block_func_0, &__ViewController__test_block_desc_0_DATA, a, &b, self, 570425344));
a = 20;
b = 20;
a_q = 20;
b_q = 20;
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
网友评论