在软件开发过程中,我们有时需要程序重复的执行某件事情,或者延迟时间去做事情,这时候我们就需要用到定时器,在iOS中,有三种常用的定时器,NSTimer, CADisplayLink, GCD dispatch_timer_t, 下面就几种定时器的常见用法进行介绍~
NSTimer
- 几种常见使用方法
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(dosomething:)];
使用上面的创建方式,会自动把timer加入MainRunloop的NSDefaultRunLoopMode中,如果使用下面这种方式创建,则需要自己手动加入runloop中:
NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(dosomething) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
- 注意:
按照上面的方法来使用基本可以解决很多问题,但是如果页面中还有scrollView时,当scrollView在滑动的时候定时器就会不起作用,这是因为在scrollView滑动的时候,MainRunloop从NSDefaultRunLoopMode模式切换到UITrackingMode,就会造成失效,解决方法是把定时器加入到NSRunLoopCommonModes中:
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
CADisplayLink
使用方法:
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(something:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[self.displayLink invalidate];
self.displayLink = nil;
CADisplayLink是一个和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的selector就会被调用一次。所以通常情况下,按照iOS设备屏幕的刷新率60次/秒(FPS)。
iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。但如果调用的方法比较耗时,超过了屏幕刷新周期,就会导致跳过若干次回调调用机会。
如果CPU过于繁忙,无法保证屏幕60次/秒的刷新率,就会导致跳过若干次调用回调方法的机会,跳过次数取决CPU的忙碌程度。
GCD
使用方法:
- 调用一次
dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(timeout * NSEC_PER_SEC));
dispatch_after(startTime, timer_manager_queue(), ^(void){
callBack(); // 这里调用执行函数
});
- 重复调用
dispatch_source_t vtimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer_manager_queue());
dispatch_source_set_event_handler(vtimer, ^{
callback();
});
// timeout 为多少秒执行一次
dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(timeout * NSEC_PER_SEC));
dispatch_source_set_timer(vtimer, startTime, timeout*NSEC_PER_SEC, 0.0);
dispatch_resume(vtimer);
在使用dispatch_time_t的时候需要注意:dispatch_resume()和dispatch_suspend()是成对出现的,调用dispatch_source_create函数的时候,默认创建的dispatch_time_t是suspend的,所以可以直接使用dispatch_resume,最近再项目中就遇到这个坑~~~