1.GCD定时器:
不受runLoop的影响,不会像NSTimer那样出现因为滑动scrollView等runLoop的mode发生变化的时候出现停止的情况,而且GCD定时器非常的精准。
//生明一个全局的dispatch_source_t,dispatch_source_t是一个OC对象,需要将它强引用
@property(nonatomic,strong)dispatch_source_t timer;
-(void)GCDTimer
{
//创建一个GCD定时器
dispatch_queue_t queue =dispatch_get_global_queue(0, 0);
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0,0, queue);
//3秒后启动定时器, 马上启动:DISPATCH_TIME_NOW
dispatch_time_t start =dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3*NSEC_PER_SEC));
uint64_t interval =(uint64_t)(2*NSEC_PER_SEC);
//设置启动时间和间隔
dispatch_source_set_timer(_timer, start, interval, 0);
//设置回调
dispatch_source_set_event_handler(_timer, ^{
//这里添加定时器事件
});
//默认暂停的,开启定时器
dispatch_resume(_timer);
}
-(void)cancelTimer
{
// 关闭定时器
// dispatch_cancel(self.timer);
// self.timer = nil;
}
2.NSTimer定时器:
存在延迟,不管是一次性的还是周期性的timer的实际触发事件的时间,都会与所加入的RunLoop和RunLoopMode有关,如果此RunLoop正在执行一个连续性的运算,timer就会被延时出发;而且NSTimer的精确度不够,Timer有个属性叫做 Tolerance(宽容度),标示了当时间点到后,容许有多少最大误差。重复性的timer遇到这种情况,如果延迟超过了一个周期,则会在延时结束后立刻执行,并按照之前指定的周期继续执行。设置为degault模式的时候,如果有滑动scrollView的话,定时器会暂停。而且在实际的项目中,如果你从一个界面进入另一个界面,你在这个界面中添加了一个NSTiner定时器,并开始计时,然后立马返回再进入,如果你没有在离开界面的时候停掉定时器,之前的添加的定时器就不会停止,从而造成一些bug。
-(void)NSTimer
{
//第一种创建方式:默认已经加入了runLoop
NSTimer *timer = [NSTimerscheduledTimerWithTimeInterval:2 target:selfselector:@selector(timerAction) userInfo:nil repeats:YES];
//第二种创建方式:这种方式创建必须手动加入runLoop;为什么NSTimer创建需要加入runLoop,看下面的关于runLoop的学习链接,详细介绍了runLoop。
[NSTimertimerWithTimeInterval:2 target:self selector:@selector(timerAction)userInfo:nil repeats:YES];
[[NSRunLoopcurrentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}
3.CADisplayLink:
屏幕刷新时调用,CADisplayLink是QuartzCore下的一个类,是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息,CADisplayLink类对应的selector就会被调用一次。所以通常情况下,按照iOS设备屏幕的刷新率60次/秒,通过frameInterval属性设置,CADisplayLink的selector每秒调用次数=60/frameInterval。比如当frameInterval设为2,每秒调用就变成30次。因此,CADisplayLink周期的设置方式略显不便。NSTimer的selector调用周期可以在初始化时直接设定,相对就灵活的多
延迟:iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度较高。但如果调用的方法比较耗时,超过了屏幕刷新周期,就会导致跳过若干次回调调用机会。
如果CPU过于繁忙,无法保证屏幕60次/秒的刷新率,就会导致跳过若干次调用回调方法的机会,跳过次数取决CPU的忙碌程度。
使用场景:从原理上可以看出,CADisplayLink适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染;或者做一些屏幕上移动的游戏动画的时候也可使用。
-(void)displayLink
{
CADisplayLink *displayLink= [CADisplayLink displayLinkWithTarget:selfselector:@selector(handleDisplayLink)];
//默认60次/秒;frameInterval为120,2秒执行一次
displayLink.frameInterval= 120;
[displayLinkaddToRunLoop:[NSRunLoop currentRunLoop]forMode:NSDefaultRunLoopMode];
//暂停
//[displayLink invalidate];
// displayLink = nil;
}
总的来说,做一般的定时器,例如发送验证码时的倒计时,不需要太高的精确度等,用NSTimer即可。如果对精确度要求很高,并且想让定时器不因为一些界面操作而暂停,可以用GCD定时器;CADisplayLink可以用作游戏中的一些动画效果等。