OC基础-Block2

84 阅读2分钟

「这是我参与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的值

3328a1e284e8b8c15c92b91c538287ef_webp.webp