iOS中的NSTimer定时器的初步使用解析

2020-01-15 14:08:02于丽

iOS,NSTimer,定时器

 

fire

我们先用 NSTimer 来做个简单的计时器,每隔5秒钟在控制台输出 Fire 。比较想当然的做法是这样的:


@interface DetailViewController ()
@property (nonatomic, weak) NSTimer *timer;
@end

@implementation DetailViewController
- (IBAction)fireButtonPressed:(id)sender {
  _timer = [NSTimer scheduledTimerWithTimeInterval:3.0f
                       target:self
                      selector:@selector(timerFire:)
                      userInfo:nil
                       repeats:YES];
  [_timer fire];
}

-(void)timerFire:(id)userinfo {
  NSLog(@"Fire");
}
@end

运行之后确实在控制台每隔3秒钟输出一次 Fire ,然而当我们从这个界面跳转到其他界面的时候却发现:控制台还在源源不断的输出着 Fire 。看来 Timer 并没有停止。

invalidate

既然没有停止,那我们在 DemoViewController 的 dealloc 里加上 invalidate 的方法:


-(void)dealloc {
  [_timer invalidate];
  NSLog(@"%@ dealloc", NSStringFromClass([self class]));
}

再次运行,还是没有停止。原因是 Timer 添加到 Runloop 的时候,会被 Runloop 强引用:

Note in particular that run loops maintain strong references to their timers, so you don't have to maintain your own strong reference to a timer after you have added it to a run loop.
然后 Timer 又会有一个对 Target 的强引用(也就是 self ):

Target is the object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated.
也就是说 NSTimer 强引用了 self ,导致 self 一直不能被释放掉,所以也就走不到 self 的 dealloc 里。

既然如此,那我们可以再加个 invalidate 按钮:


- (IBAction)invalidateButtonPressed:(id)sender {
  [_timer invalidate];
}

嗯这样就可以了。(在 SOF 上有人说该在 invalidate 之后执行 _timer = nil ,未能理解为什么,如果你知道原因可以告诉我:)