定时器dispatch source定时产生事件,可以用来发起定时执行的任务,如游戏或其它图形应用,可以使用定时器来更新屏幕或动画。你也可以设置定时器,并在固定间隔事件中检查服务器的新信息。
所有定时器dispatch source都是间隔定时器,一旦创建,会按你指定的间隔定期递送事件。你需要为定时器dispatch source指定一个期望的定时器事件精度,也就是leeway值,让系统能够灵活地管理电源并唤醒内核。例如系统可以使用leeway值来提前或延迟触发定时器,使其更好地与其它系统事件结合。创建自己的定时器时,你应该尽量指定一个leeway值。
就算你指定leeway值为0,也不要期望定时器能够按照精确的纳秒来触发事件。系统会尽可能地满足你的需求,但是无法保证完全精确的触发时间。
当计算机睡眠时,定时器dispatch source会被挂起,稍后系统唤醒时,定时器dispatch source也会自动唤醒。根据你提供的配置,暂停定时器可能会影响定时器下一次的触发。如果定时器dispatch source使用 dispatch_time 函数或 DISPATCH_TIME_NOW 常量设置,定时器dispatch source会使用系统默认时钟来确定何时触发,但是默认时钟在计算机睡眠时不会继续。
如果你使用 dispatch_walltime 函数来设置定时器dispatch source,则定时器会根据挂钟时间来跟踪,这种定时器比较适合触发间隔相对比较大的场合,可以防止定时器触发间隔出现太大的误差。
下面是定时器dispatch source的一个例子,每30秒触发一次,leeway值为1,因为间隔相对较大,使用 dispatch_walltime 来创建定时器。定时器会立即触发第一次,随后每30秒触发一次。 MyPeriodicTask 和 MyStoreTimer 是自定义函数,用于实现定时器的行为,并存储定时器到应用的数据结构。
虽然定时器dispatch source是接收时间事件的主要方法,你还可以使用其它选择。如果想在指定时间间隔后执行一个block,可以使用 dispatch_after 或 dispatch_after_f 函数。这两个函数非常类似于dispatch_async,但是只允许你指定一个时间值,时间一到就自动提交block到queue中执行,时间值可以指定为相对或绝对时间。
dispatch_source_t createTimerDispatchSource(uint64 interval,
uint64 leeway,
dispatch_queue_t queue,
dispatch_block_t block)
{
//1:创建派发源
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if(timer){
//2:配置定时器派发源,第二参数设置第一次触发时间,你可以使用dispatch_walltime函数,也可以使用dispatch_time或DISPATCH_TIME_NOW
dispatch_source_set_timer(timer, dispatch_walltime(NULL, interval), interval, leeway);
//3:设置事件响应体
dispatch_source_set_event_handler(timer, block);
//4:启动派发源
dispatch_resume(timer);
}
return timer;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"==========定时器派发源===========");
__block int count = 0;
dispatch_source_t timer = createTimerDispatchSource(3ull * NSEC_PER_SEC,//事件间隔时间
0ull * NSEC_PER_SEC,//偏差,0偏差最好(虽然达不到)
dispatch_get_main_queue(),
^{
NSLog(@"on timer");
count++;
});
while (YES) {
if (count == 3) {
dispatch_source_cancel(timer);
break;
}
[[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
}
}
return 0;
}
所有定时器dispatch source都是间隔定时器,一旦创建,会按你指定的间隔定期递送事件。你需要为定时器dispatch source指定一个期望的定时器事件精度,也就是leeway值,让系统能够灵活地管理电源并唤醒内核。例如系统可以使用leeway值来提前或延迟触发定时器,使其更好地与其它系统事件结合。创建自己的定时器时,你应该尽量指定一个leeway值。
就算你指定leeway值为0,也不要期望定时器能够按照精确的纳秒来触发事件。系统会尽可能地满足你的需求,但是无法保证完全精确的触发时间。
当计算机睡眠时,定时器dispatch source会被挂起,稍后系统唤醒时,定时器dispatch source也会自动唤醒。根据你提供的配置,暂停定时器可能会影响定时器下一次的触发。如果定时器dispatch source使用 dispatch_time 函数或 DISPATCH_TIME_NOW 常量设置,定时器dispatch source会使用系统默认时钟来确定何时触发,但是默认时钟在计算机睡眠时不会继续。
如果你使用 dispatch_walltime 函数来设置定时器dispatch source,则定时器会根据挂钟时间来跟踪,这种定时器比较适合触发间隔相对比较大的场合,可以防止定时器触发间隔出现太大的误差。
下面是定时器dispatch source的一个例子,每30秒触发一次,leeway值为1,因为间隔相对较大,使用 dispatch_walltime 来创建定时器。定时器会立即触发第一次,随后每30秒触发一次。 MyPeriodicTask 和 MyStoreTimer 是自定义函数,用于实现定时器的行为,并存储定时器到应用的数据结构。
虽然定时器dispatch source是接收时间事件的主要方法,你还可以使用其它选择。如果想在指定时间间隔后执行一个block,可以使用 dispatch_after 或 dispatch_after_f 函数。这两个函数非常类似于dispatch_async,但是只允许你指定一个时间值,时间一到就自动提交block到queue中执行,时间值可以指定为相对或绝对时间。
dispatch_source_t createTimerDispatchSource(uint64 interval,
uint64 leeway,
dispatch_queue_t queue,
dispatch_block_t block)
{
//1:创建派发源
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if(timer){
//2:配置定时器派发源,第二参数设置第一次触发时间,你可以使用dispatch_walltime函数,也可以使用dispatch_time或DISPATCH_TIME_NOW
dispatch_source_set_timer(timer, dispatch_walltime(NULL, interval), interval, leeway);
//3:设置事件响应体
dispatch_source_set_event_handler(timer, block);
//4:启动派发源
dispatch_resume(timer);
}
return timer;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"==========定时器派发源===========");
__block int count = 0;
dispatch_source_t timer = createTimerDispatchSource(3ull * NSEC_PER_SEC,//事件间隔时间
0ull * NSEC_PER_SEC,//偏差,0偏差最好(虽然达不到)
dispatch_get_main_queue(),
^{
NSLog(@"on timer");
count++;
});
while (YES) {
if (count == 3) {
dispatch_source_cancel(timer);
break;
}
[[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
}
}
return 0;
}