Block是什么
Block也是一个OC对象,内部也有isa指针。
扩展:
instance对象的isa指向class对象
class对象的isa指向meta-class对象
meta-class对象的isa指向基类的meta-class对象
void (^block)(void) = ^{
NSLog(@"Hello");
};
NSLog(@"%@", [block class]);
NSLog(@"%@", [[block class] superclass]);
NSLog(@"%@", [[[block class] superclass] superclass]);
NSLog(@"%@", [[[[block class] superclass] superclass] superclass]);
2020-11-09 22:24:30.042560+0800 Interview01-Block的本质[1489:30598] __NSGlobalBlock__
2020-11-09 22:24:30.043005+0800 Interview01-Block的本质[1489:30598] __NSGlobalBlock
2020-11-09 22:24:30.043103+0800 Interview01-Block的本质[1489:30598] NSBlock
2020-11-09 22:24:30.043163+0800 Interview01-Block的本质[1489:30598] NSObject
Block的类型
__NSGlobalBlock__(_NSConcreteGlobalBlock)(存放在数据区) (不访问auto变量的block 即便是访问了static局部变量 或者全局变量)
__NSStackBlock__(_NSConcreteStackBlock)(存放在栈区 系统管理内存)(访问了auto变量:auto变量就是局部变量)
__NSMallocBlock__(_NSConcreteMallocBlock) (存放在堆区 程序员管理内存) (__NSStackBlock__调用了copy)
不同类型变量的捕获方式
1、局部变量和block
使用局部变量的block
int main(int argc, const char * argv[]) {
@autoreleasepool {
int age = 10;
block = ^{
// age的值捕获进来(capture)
NSLog(@"age is %d, ", age);
};
age = 20;
block();
}
return 0;
}
clang编译后的底层代码
struct __test_block_impl_0 {
struct __block_impl impl;
struct __test_block_desc_0* Desc;
int age;
__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
可以看到,在block的内部多了成员变量_age,并且在构造这个block时,会把age的值直接传进去,几_age=age,可以看出来这时是block捕获了局部变量,并且进行了值传递。
2、静态局部变量
int main(int argc, const char * argv[]) {
@autoreleasepool {
// auto:自动变量,离开作用域就销毁
auto int age = 10;
static int height = 10;
void (^block)(void) = ^{
// age的值捕获进来(capture)
NSLog(@"age is %d, height is %d", age, height); // 10 20
};
age = 20;
height = 20;
block();
}
return 0;
}
编译后的结果:
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;
}
};
//定义的时候
block = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, age, &height));
//执行的时候
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {
int age = __cself->age; // bound by copy
int *height = __cself->height; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_d2875b_mi_0, age, (*height));
}
可以看出来age传递的是值,但是静态局部变量height传递的是指针。
3、全局变量和block
int age_ = 10;
static int height_ = 10;
void (^block)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
void (^block)(void) = ^{
NSLog(@"age is %d, height is %d", age_, height_);
};
age_ = 20;
height_ = 20;
block();
}
return 0;
}
编译后:
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;
}
};
//调用函数的时候
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_d2875b_mi_0, age_, height_);
}
可以看到全局变量没有捕获到block内部,是直接访问的,所以每次访问都能获得最新值。
未完待续
参考文档:文章来源:https://www.toymoban.com/news/detail-797313.html
block ios 深入理解 ios __block的作用_imking的技术博客_51CTO博客
iOS OC基础知识笔记_ios oc y-CSDN博客文章来源地址https://www.toymoban.com/news/detail-797313.html
到了这里,关于iOS block以及变量捕获的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!