iOS准确的Timer

前言

 没有绝对准确的Timer,相对而言推荐CADisplayLink。


NSTimer


用法一:

scheduledTimerWithTimeInterval创建的timer:默认立即在当前线程runloop的NSDefaultRunLoopMode下运行,当前线程如果是主线程,如果切换到其他model(如NSEventTrackingRunLoopMode),timer不会被call,造成定时器不准确。此时需要将timer提交到NSRunLoopCommonModes模式。

// 创建定时器1

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(call) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];


用法二

timerWithTimeInterval创建的timer默认不添加到任何runloop中,需要将timer提交到NSRunLoopCommonModes模,并开启runloop。

// 创建定时器2

NSTimer *timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(call) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

//如果是子线程

[[NSRunLoop currentRunLoop] run];

dispatch_source_t

使用:

//创建GCD timer资源, 第一个参数为源类型, 第二个参数是资源要加入的队列

_timer =dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0, queue);

//设置timer信息

dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 1ull * NSEC_PER_SEC, 0);

//设置timer的触发事件

dispatch_source_set_event_handler(_timer, ^{

   //do something

});

//激活timer对象

dispatch_resume(_timer);

特点:

需要持有dispatch_source_t变量。

优点:不受当前runloopMode的影响。

缺点:其计时效应仍不是百分之百准确的;另外,他的触发事件也有可能被阻塞,当GCD内部管理的所有线程都被占用时,其触发事件将被延迟

CADisplayLink

特点:

CADisplayLink是一个和屏幕刷新率同步的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息,CADisplayLink类对应的selector就会被调用一次,所以可以使用CADisplayLink做一些和屏幕操作相关的操作。

缺点:

如果CPU操作饱和,影响了屏幕刷新,也会影响计时器的精准。

// 创建displayLink

displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(test)];

// 将创建的displaylink添加到runloop中,否则定时器不会执行

[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

你可能感兴趣的:(iOS准确的Timer)