「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战」。
static类型局部变量(指针传递/地址传递)
拿到的是static局部变量最新的值(因为static的值会一直保留在内存中)
static int age = 10;
void (^newBlock)(void) = ^(void){
NSLog(@"测试Block1 age = %d",age);
};
age = 30;
newBlock();
打印结果
2022-02-24 10:32:54.982175+0800 DoBlock[69542:1863431] 测试Block1 age = 30
查看源码
static int age = 10;
void (*newBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &age));//此处获取的是age指针,也就是其地址
age = 30;//最后再将30传递到block内部
((void (*)(__block_impl *))((__block_impl *)newBlock)->FuncPtr)((__block_impl *)newBlock);
全局变量(没有被block内部所捕捉,因为全局变量谁都可以访问)
先上代码
#import <Foundation/Foundation.h>
int age = 10;
static int height = 10;
int main(int argc, const char * argv[]) {
@autoreleasepool {
void (^newBlock)(void) = ^(void){
NSLog(@"测试Block1 age = %d,height = %d",age,height);
};
age = 30;
height = 30;
newBlock();
}
return 0;
}
打印结果
2022-02-24 10:55:40.276357+0800 DoBlock[69897:1878721] 测试Block1 age = 30,height = 30
上源码
#pragma clang assume_nonnull end
int age = 10;
static int height = 10;
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;
}
};
//可以发现没有height和age被捕捉
取值的时候
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_gr_dh8_mn8x2vv87_1mpf799qrr0000gn_T_main_ba7ddd_mi_0,age,height);
}
//此处直接拿到height,age的值即可
来个测试 1以下代码中self,是如何被访问的,有没有被block捕捉
- (void)test {
void (^block)(void) = ^{
NSLog(@"------%p",self);
};
block();
}
答案:肯定有,看源码
struct __MJPerson__test_block_impl_0 {
struct __block_impl impl;
struct __MJPerson__test_block_desc_0* Desc;
MJPerson *self; //有被捕捉
__MJPerson__test_block_impl_0(void *fp, struct __MJPerson__test_block_desc_0 *desc, MJPerson *_self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
分析
从源码得知self有被捕获,所以得出结论,self为局部变量,OC的test方法底层会转换成以下内容
//-(void)test{}
static void _I_MJPerson_test(MJPerson * self, SEL _cmd) {
void (*block)(void) = ((void (*)())&__MJPerson__test_block_impl_0((void *)__MJPerson__test_block_func_0, &__MJPerson__test_block_desc_0_DATA, self, 570425344));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
//-(instancetype)initWithName:(NSString *)name;
static instancetype _Nonnull _I_MJPerson_initWithName_(MJPerson * self, SEL _cmd, NSString * _Nonnull name) {
if (self = ((MJPerson *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("MJPerson"))}, sel_registerName("init"))) {
((void (*)(id, SEL, NSString * _Nonnull))(void *)objc_msgSend)((id)self, sel_registerName("setName:"), (NSString * _Nonnull)name);
}
return self;
}
- (void)test {}
void test (MJPerson * self ,SEL _cmd){}//默认接收两个参数
//也就相当于
- (void)test(MJPerson * self ,SEL _cmd) {}
//参数为局部变量,所以self为局部变量,所以肯定会被block内部捕获,这就是我们为什么能在方法内部访问self和_cmd
测试2以下代码中_name,是如何被访问的,有没有被block捕捉
- (void)test {
void (^block)(void) = ^{
NSLog(@“———%@”,_name);
};
block();
}
分析,先判读是不全局变量还是局部变量,_name - >self->_name.,self为局部变量,所以self->_name为局部变量,那也就是说_name为局部变量,
所以整个过程,先捕获self,再访问self里面的_name,所以不是单独对_name捕获而是对self的捕获,最终获得_name的值