iOS dispatch_after延迟执行导致延迟dealloc

2021-04-15 17:04:07 浏览数 (1)

我们新建一个NewViewController,在开始的ViewController写如下代码

代码语言:javascript复制
- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.frame = CGRectMake(100, 100, 100, 50);
    btn.backgroundColor = [UIColor brownColor];
    [btn addTarget:self action:@selector(jump) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    
}

-(void)jump{
    NewViewController *newVC = [[NewViewController alloc]init];
    [self presentViewController:newVC animated:YES completion:nil];
}

然后在NewViewController里:

代码语言:javascript复制
-(void)dealloc{
    NSLog(@"--------------dealloc");
}

- (void)viewDidLoad {
    [super viewDidLoad];
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.frame = CGRectMake(100, 300, 100, 50);
    btn.backgroundColor = [UIColor brownColor];
    [btn addTarget:self action:@selector(jump) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self log];
        NSLog(@"--------------after");
    });
    
}

-(void)log{
    NSLog(@"--------------log");
}

-(void)jump{
    NSLog(@"--------------dismiss");
    [self dismissViewControllerAnimated:YES completion:nil];
}

运行之后,我们一跳进newVC里面返回,这时候:

image.png

结果说明我们dismiss的时候,newVC还没有被释放,dealloc方法在dispatch_after延迟方法执行之后才会走,原因就是dispatch_after强引用了self(即newVC),等强引用过去,self才能得到释放走dealloc

接下来,我们在dispatch_after里把 self 用 __weak修饰,block里把self改为weakself,我们还是一样的操作流程,看看结果:

代码语言:javascript复制
- (void)viewDidLoad {
    [super viewDidLoad];
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.frame = CGRectMake(100, 300, 100, 50);
    btn.backgroundColor = [UIColor brownColor];
    [btn addTarget:self action:@selector(jump) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [weakSelf log];
        NSLog(@"--------------after");
    });
    
}

image.png

当我们用weak修饰self时,dispatch_after并没有强引用self,所以我们dissmiss时,dealloc立马就会走,然后10s后,dispatch_after的执行函数还是会执行,输出了after,但是没有输出log,这是因为用的weakSelfdissmiss后,newVC已经被释放,这时候代码 [weakSelf log];等同于[nil log];,所以才不会输出log。

使用注意

虽然dispatch_after里直接调用self不会造成循环引用,但当我们dispatch_after延迟时间过长的时候,需要考虑是否要及时释放当前对象,如果需要,尽量使用weakSelf这种方式,如果真有需要用到self完成一些操作再释放的需求,可以按需编写代码。

0 人点赞