项目里用到定时器时,看同事是这么写的:
@property (nonatomic,strong) dispatch_source_t timer;
if (!self.timer) {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC));
uint64_t interval = (uint64_t)(1 * NSEC_PER_SEC);
dispatch_source_set_timer(self.timer, start, interval, 0);
dispatch_source_set_event_handler(self.timer, ^{
// NSLog(@"定时器开启中........");
dispatch_async(dispatch_get_main_queue(), ^{
// 主线程添加事件处理
});
});
//启动定时器
dispatch_resume(self.timer);
}
/**
* 移除定时器
*/
- (void)removeTimer {
if (self.timer) {
dispatch_source_cancel(self.timer);
self.timer = nil;
}
}
跟自己写的NSTimer档次不一样,感觉这个逼格好高啊,然后就研究了下 dispatch_sourcer在定时器里的使用,如下。
定时器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_t CreateDispatchTimer(uint64_t interval,
uint64_t leeway,
dispatch_queue_t queue,
dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
0, 0, queue);
if (timer)
{
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer;
}
void MyCreateTimer()
{
dispatch_source_t aTimer = CreateDispatchTimer(30ull * NSEC_PER_SEC,
1ull * NSEC_PER_SEC,
dispatch_get_main_queue(),
^{ MyPeriodicTask(); });
// Store it somewhere for later use.
if (aTimer)
{
MyStoreTimer(aTimer);
}
}
虽然定时器dispatch source是接收时间事件的主要方法,你还可以使用其它选择。如果想在指定时间间隔后执行一个block,可以使用 dispatch_after 或 dispatch_after_f函数。这两个函数非常类似于dispatch_async,但是只允许你指定一个时间值,时间一到就自动提交block到queue中执行,时间值可以指定为相对或绝对时间。
然后我总结了下用dispatch_source写定时器的优缺点
优点:
1、可以暂停,继续。 不用像NSTimer一样需要重新创建。
2、性能较好。
缺点:
1、每次resume都会先执行一次。
共同点:
1、如果不手动释放就不会走dealloc。
2、不精确