定时器是否存在循环引用

iOS笔记——Hey, 定时器!

写这篇文章也是受到上篇文章的启发,想好好测试一下NSTimer。毕竟是一个常用的知识点。以下观点也仅供参考,求各位大神多提点。
首先要说明的是:

[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];

这种匿名的方式是完全不能使用的,因为该定时器是会永远存在,并且它“看上去”强引用了target,也就是这里的self也不会释放。

推荐一个我以前的写法,估计基本都这样:

@property (nonatomic, strong) NSTimer *timer;

- (void)addTimer {
    self.timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

- (void)removeTimer {
    [self.timer invalidate];
    self.timer = nil;
}

经过测试,虽然这里使用strong强引用了timer,但是同样在pop控制器并且执行removeTimer之后,控制器执行了dealloc,并且定时器停止了。也不存在循环引用问题。

这里分析一下:为什么前面那种写法,会导致timer、self一直存在呢?我觉得并不是循环引用的问题,而是scheduledTimerWithTimeInterval导致在runloop中,对timer、self有了强引用。如果timer执行invalidate,则在runloop中,就会取消对timer及self的强引用了。也不经回想一下UIControl,然后addTarget后,该控件就对target进行了强引用?!

另外苹果对NSTimer还提供了block方法:scheduledTimerWithTimeInterval: repeats: block:timerWithTimeInterval: repeats: block:
这里经过测试,只要timer执行了invalidate,同样控制器执行了dealloc,并且定时器停止了。
不过发现如果timer不执行invalidate,这种方式,在block中使用了self而不是weakSelf,self将不会被释放。
我的理解是这样的:因为timer被添加进runloop了,所以肯定不会释放。而timer对block应该进行了强引用,block对其中使用了的self又进行了强引用,从而导致self不会被释放。如果使用weakSelf,timer会存在,time中的block存在但不对weakSelf强引用,所以weakSelf该释放就会释放。

//    __weak typeof(self) weakSelf = self;
    [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"block - %@ - scheduledTimerWithTimeInterval", self);
//        NSLog(@"block - %@ - scheduledTimerWithTimeInterval", weakSelf);
    }];

你可能感兴趣的:(定时器是否存在循环引用)