在iOS开发过程中,定时器通常用在这样的情况下:在某个时间后去执行某个方法,或者是按照一个周期循环执行某个方法。大概呢,有以下三种方案:
NSTimer
CADisplayLink
GCD
关于NSTimer
NSTimer的初始化方法:
1234567+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;部分参数说明
repeats: 设置定时器是否循环执行,YES表示循环执行,NO将只执行一次。
NSTimeInterval: 执行之前等待的时间
target: 需要执行方法的对象
selector: 需要执行的方法说明:不是以
scheduledTimerWithTimeInterval:
方式初始化的,需要手动地将timer添加到一个runloop中。而以scheduledTimerWithTimeInterval:
方式初始化,会自动把timer加入MainRunloop的NSDefaultRunLoopMode中。12NSTimer *timer = [NSTimer timerWithTimeInterval:8 target:self selector: (timerAction) userInfo:nil repeats:YES];[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];其他方法及属性
1- (void)fire;该方法用来立即触发该定时器;
官方解释:You can use this method to fire a repeating timer without interrupting its regular firing schedule. If the timer is non-repeating, it is automatically invalidated after firing, even if its scheduled fire date has not arrived.
意思是说:在重复执行的定时器中调用此方法后立即触发该定时器,但不会中断其之前的执行计划;在不重复执行的定时器中调用此方法,立即触发后,就会使这个定时器失效。
1- (void)invalidate;- 该方法是唯一的,将计时器从runloop中移出的方法。
12timer.fireDate = [NSDate distantPast]; // 开启定时器timer.fireDate = [NSDate distantFuture]; // 关闭定时器- 如果希望先停止,然后再某种情况下再次开启运行timer,可以使用属性:
fireDate
。
12345678// 这是一个只读的属性,用来获取定时器调用的间隔时间。@property (readonly) NSTimeInterval timeInterval;// 7.0之后新增的一个属性,因为NSTimer并不完全精准,通过这个值设置误差范围。@property NSTimeInterval tolerance;// 判断定时器是否有效@property (readonly, getter=isValid) BOOL valid;
关于CADisplayLink
CADisplayLink是一个能让我们
以和屏幕刷新率同步的频率
将特定的内容画到屏幕上的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息,CADisplayLink类对应的selector就会被调用一次。所以通常情况下,按照iOS设备屏幕的刷新率60次/秒
。因此CADisplayLink的selector默认调用周期是每秒60次,这个周期可以通过frameInterval属性设置,CADisplayLink的selector每秒调用次数=60/frameInterval。比如当frameInterval设为2,每秒调用就变成30次。CADisplayLink的方法及属性
123456789101112131415+ (CADisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel;- (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode;- (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode;- (void)invalidate;// 只读的CFTimeInterval值,表示屏幕显示的上一帧的时间戳,这个属性通常被target用来计算下一帧中应该显示的内容。@property(readonly, nonatomic) CFTimeInterval timestamp;// 表示两次屏幕刷新之间的时间间隔,**该属性在target的selector被首次调用以后才会被赋值。selector的调用间隔时间计算方式是:时间=duration×frameInterval**。@property(readonly, nonatomic) CFTimeInterval duration;@property(getter=isPaused, nonatomic) BOOL paused;// 用来设置间隔多少帧调用一次selector方法,默认值是1,即每帧都调用一次。@property(nonatomic) NSInteger frameInterval;示例
1234567self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];self.displayLink.frameInterval = 2;[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];// 关闭定时器[self.displayLink invalidate];self.displayLink = nil;CADisplaylink和NSTimer的区别
CADisplayLink: 使用场合相对专一,适合做UI的不停重绘,比如
自定义动画引擎或者视频播放的渲染
。在UI相关的动画或者显示内容使用CADisplayLink显得很方便,因为不需要格外关心屏幕的刷新频率了,它本身就是跟屏幕刷新同步的。
NSTimer: 使用范围要广泛的多,各种需要单次或者循环定时处理的任务
都可以使用。
关于GCD
执行一次
12345double delayInSeconds = 2.0;dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);dispatch_after(popTime, dispatch_get_main_queue(), ^(void){//执行事件});重复执行
12345678NSTimeInterval period = 1.0;dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0);dispatch_source_set_event_handler(_timer, ^{NSLog(@"GCD continue");});dispatch_resume(_timer);