OC底层 - block捕获变量

block是oc语言的一种代码块, 底层实现为oc对象, 代码块封装在一个函数中, 函数作为该oc对象的一个变量, 调用时, 直接调用该函数;

什么情况下block会捕获变量呢?

局部变量(自动变量)

如果block中使用了方法中的局部变量, 如下:

-(void)test
{
    int age = 10;
    void(^block1)(void) ^{
        NSLog(@"%ld",age);
    };
}

因为局部变量(自动变量)在test方法结束的时候会被自动释放, 但是block可能此时还没调用, 这时候block就需要将age变量据为己有, 直接捕获变量age, 作为自己的一个变量;

当变量被捕获时, 即使修改该变量, block内部的age也不会改变, 因为外部的age与block内部的age已经不是同一个age;

-(void)test
{
    int age = 10;
    void(^block1)(void) ^{
        NSLog(@"%ld",age);
    };
    age = 20;
    block1();
}

局部静态变量

因为静态变量并不会因为test方法的结束而释放, 这时候也会捕获静态局部变量age, 但是这时候是捕获的age的地址, 外部修改age, 会直接修改block中的内容;

-(void)test
{
    static int age = 10;
    void(^block1)(void) ^{
        NSLog(@"%ld",age);
    };
    age = 20;
    block1();
}

全局变量

因为全局变量的声明周期伴随着对象的声明周期, 所以block并不会捕获age, 而是直接调用外部的age;

int age = 10;
static int age2 = 10;
-(void)test
{
    
    void(^block1)(void) ^{
        NSLog(@"%ld",age);
    };
    age = 20;
    block1();
}

self

oc编程的实现原理为, 方法内部有两个默认的变量, 一个是self,当前对象的指针 , 一个是sel, 当前方法的地址, 所以self是方法test的内部局部变量, 所以self会被捕获, 捕获的是地址;

-(void)test
{
    
    void(^block1)(void) ^{
        NSLog(@"%@",self);
    };
    block1();
}

对象成员变量

对于成员变量而言, 在block中调用_name, 其实是self->_name 这样子调用的, self是局部变量, 会被捕获, block内部根据捕获的self调用_name;

对象的成员变量
_name;
-(void)test
{
    
    void(^block1)(void) ^{
        NSLog(@"%@",_name);
    };
    block1();
}

猜你喜欢

转载自blog.csdn.net/Batac_Lee/article/details/110430771