Block常见问题-day2记录笔记

420 阅读1分钟

针对block的常见应用,从底层出发,列举了如下几个经典的问题。

  • block 全局变量和自动变量;
  • block变量的引用;

一、block内部修改外部的变量方式

在myBlock修改age值为20的办法及其原理?

int age = 10;
void(^myBlock)(void) = ^{

    NSLog(@"age--%d",age);
};
 myBlock();

1、在age变量添加修饰符static,这样一来myBlock 内部捕获的成员变量将是 int *age,捕获的内存地址,通过地址传递,就可以直接修改age的值。 其myBlock的结构如下:

struct __main_block_impl_0{
    struct __block_impl;
    struct __block_des;
    int * age;  //指针
}

2、将age变成全局变量,这样block即可访问并使用改变量。全局变量任何函数任何地方都可调用。

3、通过__block关键字来修饰。其底层原理:__block会将age封装成一个 __Block_byref_age_0 的一个对象,对象内部有一个 __Block_byref_age_0__forwarding 指针指向自己,所以在修改值的时候会执行 age->__forwarding->age 在修改和取值,这样一来就达到了修改的操作。

block本质结构如下:

struct __main_block_impl_0{
    ...
    __Block_byref_age_0 *age;//本质是对象
}

__Block_byref_age_0 本质结构如下:

struct __Block_byref_age_0{
    void * __isa;
    __Block_byref_age_0 *__forwarding;
    int __flags;
    int __size;
    int age;
}

二、block变量的引用。

    WSTObjct * wstObj = [[WSTObjct alloc] init];
    
    __weak WSTObjct * blockWstObj = wstObj;
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        NSLog(@"1------%@",blockWstObj);
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            
            NSLog(@"2------%@",wstObj);
        });
    });
    
    NSLog(@"touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event");
    

WSTObject 在销毁时,我们打印了dealloc

@implementation WSTObjct

- (void)dealloc
{
    NSLog(@"WSTObjct 对象销毁");
}

@end

执行代码后,WSTObjct 对象销毁 在第几秒后打印?

答案:第三秒后打印,图下图所示;

首先wstObj是局部变量,block会进行捕获变量到__main_block_impl。编译器会发现第二个dispatch_after中的wstObj和block中进行了强引用,所以block的销毁时wstObj才销毁。