NSTimer:依赖于 NSRunLoop的定时触发器,用于定时执行某个动作。
- 创建
- 暂停
- 恢复
- 销毁
- 持续触发
创建:
只有把 NSTimer加入 NSRunLoop,NSTimer才会触发。
@property (nonatomic, retain) NSTimer *timer;
- (void)testNSTimer {
// 方法一(常用):该方法会把 NSTimer加入 NSRunLoop
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(output) userInfo:nil repeats:YES];
// 方法二:新建 NSTimer,手动添加到 NSRunLoop
_timer = [[NSTimer alloc] initWithFireDate:[NSDate date] interval:1.0f target:self selector:@selector(output) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
// 方法三:新建 NSTimer,手动添加到 NSRunLoop
_timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(output) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
// 子线程新建 NSTimer
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(output) userInfo:nil repeats:YES];
// 注意:子线程的 NSRunLoop默认是关闭的,需要run才会执行
[[NSRunLoop currentRunLoop] run];
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
- (void)output {
NSLog(@"fire");
}
暂停:
- (void)pauseTimer {
if ([_timer isValid]) {
// 在一个遥远的未来触发,即:暂停
[_timer setFireDate:[NSDate distantFuture]];
}
}
恢复:
- (void)resumeTimer {
// 当前时间触发
[_timer setFireDate:[NSDate date]];
}
销毁:invalidate
重复触发定时器时,如果不停止,它会一直执行下去,所以要在viewDidDisappear或者viewWillDisappear销毁它。
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_timer invalidate];
}
为什么不是在dealloc销毁?
首选,NSTimer创建的时候会强引用self(ViewController);NSTimer一直触发,就不会被销毁,它引用的ViewController也就不会执行dealloc方法,因此在dealloc方法中执行销毁动作是没有用的。
持续触发:
拖动UIScrollView会影响NSTimer的触发,把NSTimer加到NSRunLoopCommonModes即可解决。
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
什么是NSRunLoopCommonModes?为什么选它?
首先查看NSRunLoopCommonModes的官方解释:
Objects added to a run loop using this value as the mode are monitored by all run loop modes that have been declared as a member of the set of “common" modes
大概意思是:所有以添加对象到NSRunLoop的方式形成的NSRunLoopMode都会成为mode集合的一员,这个mode集合叫做NSRunLoopCommonModes。
也就是说 NSRunLoopCommonModes包含了几乎所有 NSRunLoopMode。
我们知道,使用方法一创建的NSTimer添加在 NSRunLoop的默认模式NSDefaultRunLoopMode,当拖动 UIScrollView时,NSRunLoop的模式会切换为NSEventTrackingRunLoopMode,它的官方解释如下:
A run loop should be set to this mode when tracking events modally, such as a mouse-dragging loop.
大概意思是:类似于拖拽鼠标的动作都会被计入 NSEventTrackingRunLoopMode。
那么处在 NSDefaultRunLoopMode模式的 NSTimer就不会继续触发。
所以把NSTimer加入NSRunLoopCommonModes的 NSRunLoop后不会受UIScrollView拖动的影响。