timer

来讲讲timer的使用,在我们平时的开发工作中使用到timer的地方也比较多,但是在我们日常使用timer,很多时候我们都错误的使用,或者说根本不了解timer应该怎样使用,使用期间会有哪些问题,今天我们就来讲一讲。

timer造成的循环引用

为什么会有timer循环引用这种问题呢?还是先抛出一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@interface PPSViewController ()

@property (nonatomic, strong) NSTimer *timer;

@end

@implementation PPSViewController

- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(doSomething) userInfo:nil repeats:YES];
[self.timer fire];

}

- (void)doSomething {
NSLog(@"do");
}

- (void)dealloc {
NSLog(@"dealloc");
[self.timer invalidate];
}

- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
NSLog(@"viewDidDisappear");
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

@end

首先请思考一下,上面的代码有什么问题 ?


我们来看一下输出:

1
2
3
4
5
6
7
8
9
10
2017-07-24 16:30:42.504 PPSTimer[8438:392065] do
2017-07-24 16:30:43.504 PPSTimer[8438:392065] do
2017-07-24 16:30:44.504 PPSTimer[8438:392065] do
2017-07-24 16:30:45.504 PPSTimer[8438:392065] do
2017-07-24 16:30:46.505 PPSTimer[8438:392065] do
2017-07-24 16:30:47.204 PPSTimer[8438:392065] viewDidDisappear
2017-07-24 16:30:47.504 PPSTimer[8438:392065] do
2017-07-24 16:30:48.504 PPSTimer[8438:392065] do
2017-07-24 16:30:49.504 PPSTimer[8438:392065] do
2017-07-24 16:30:50.504 PPSTimer[8438:392065] do

解释一下我的操作,我首先在即将进入该VC的时候,启动了一个timer 并且加入到runloop中,开始执行一项循环任务,然后我希望的是在退出这个VC的时候这个timer停止

但是好像输出并不是像我预想的那样? 那我们再修改一下 将timer设置成weak 是否能够达到我们想要的效果

输出证明还是不行

那我们再改一下

1
2
3
4
5
6
7
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self)weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakSelf selector:@selector(doSomething) userInfo:nil repeats:YES];
[self.timer fire];

}

这样修改过后,执行效果和之前没什么差别。。。

根据官方的文档

https://developer.apple.com/documentation/foundation/nstimer

timer在固定时间被触发,执行某项任务的实现:

  • timer会被添加到runloop中执行,需要指定timer的运行模式,默认情况下是NSRunLoopDefault
  • runloop会对timer强引用
  • timer会对target强引用
  • timer的执行时间并不会很准确,只能是runloop中循环到了,开始执行
  • timer必须通过invalidate才能停止运行

知道了上面几点,其实也就不难理解了

看这张图,结合我们上面的代码,如果在viewController的dealloc中invalidate这个timer,那么这个timer永远不会被停止,timer对viewcontroller有一个强引用,dealloc这个方法永远不会被调用

欢迎关注微博:ppsheep_Qian

http://weibo.com/ppsheep

欢迎关注公众号