GCD计时器
大家在开发的过程中,经常会用到定时器,通常的做法可能就是NSTimer
,了解过GCD的同学可能会接触到dispatch source
的概念,dispatch source
是一个监视某些类型事件的对象。当这些事件发生时,它自动将一个block放入一个dispatch queue
的执行例程中。
dispatch source
支持的事件有很多,__MAC_10_6支持的事件如下:(请参考source.h
)
* DISPATCH_SOURCE_TYPE_DATA_ADD: n/a
* DISPATCH_SOURCE_TYPE_DATA_OR: n/a
* DISPATCH_SOURCE_TYPE_MACH_SEND: mach port (mach_port_t)
* DISPATCH_SOURCE_TYPE_MACH_RECV: mach port (mach_port_t)
* DISPATCH_SOURCE_TYPE_MEMORYPRESSURE n/a
* DISPATCH_SOURCE_TYPE_PROC: process identifier (pid_t)
* DISPATCH_SOURCE_TYPE_READ: file descriptor (int)
* DISPATCH_SOURCE_TYPE_SIGNAL: signal number (int)
* DISPATCH_SOURCE_TYPE_TIMER: n/a
* DISPATCH_SOURCE_TYPE_VNODE: file descriptor (int)
* DISPATCH_SOURCE_TYPE_WRITE: file descriptor (int)
这里主要说一下计时器,对其他事件感兴趣的同学可以网上查些资料。
GCD计时器的使用通常由一下几个函数构成:
1.dispatch_source_create
创建一个新的调度源来监视低级别的系统对象和自动提交处理程序块来响应事件调度队列
2.dispatch_source_set_timer
为一个定时源设置一个开始时间、事件间隔、误差值
我们来看看这个函数原型
dispatch_source_set_timer(dispatch_source_t source,
dispatch_time_t start,
uint64_t interval,
uint64_t leeway);
source
当然就是我们第一步创建的调度源。
start
是我们设定的计时开始时间,可以dispatch_time
和 dispatch_walltime
函数来创建它们,至于dispatch_time
跟dispatch_walltime
的区别,stackoverflow的解释是这样的
dispatch_time stops running when your computer goes to sleep. dispatch_walltime continues running. So if you want to do an action in one hour minutes, but after 5 minutes your computer goes to sleep for 50 minutes, dispatch_walltime will execute an hour from now, 5 minutes after the computer wakes up. dispatch_time will execute after the computer is running for an hour, that is 55 minutes after it wakes up.
但是我自己在iPhone上测试的时候好像并没有什么卵用,难道是Mac跟iPhone的机制不一样?有兴趣的同学可以去深究一下,找到答案可以告诉我一下。
interval
就是时间间隔了,这个不用多说了。
leeway
,对这个参数的理解,我觉得http://www.dreamingwish.com上Seven's
同学的解释很直观也很易懂:
“这个参数告诉系统我们需要计时器触发的精准程度。所有的计时器都不会保证100%精准,这个参数用来告诉系统你希望系统保证精准的努力程度。如果你希望一个计时器没五秒触发一次,并且越准越好,那么你传递0为参数。另外,如果是一个周期性任务,比如检查email,那么你会希望每十分钟检查一次,但是不用那么精准。所以你可以传入60,告诉系统60秒的误差是可接受的。这样有什么意义呢?简单来说,就是降低资源消耗。如果系统可以让cpu休息足够长的时间,并在每次醒来的时候执行一个任务集合,而不是不断的醒来睡去以执行任务,那么系统会更高效。如果传入一个比较大的leeway给你的计时器,意味着你允许系统拖延你的计时器来将计时器任务与其他任务联合起来一起执行。”
3.dispatch_source_set_event_handler
给一个调度源设置一个时间处理块。
4.dispatch_source_cancel
异步取消一个调度源,防止任何进一步调用它的事件处理块的发生
5.dispatch_source_set_cancel_handler
给一个调度源设置一个取消处理块
6.dispatch_resume
同步等待一个对象,直到超时
以上几个步骤中,dispatch_source_set_event_handler与dispatch_source_cancel必须一起出现,否则调度源处理块不会执行。
下面附一段完整的代码,演示一个简单的10秒倒计时的功能:
- (void)start
{
__block int32_t timeOutCount=10;
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(timer, ^{
OSAtomicDecrement32(&timeOutCount);
if (timeOutCount == 0) {
NSLog(@"timersource cancel");
dispatch_source_cancel(timer);
}
});
dispatch_source_set_cancel_handler(timer, ^{
NSLog(@"timersource cancel handle block");
});
dispatch_resume(timer);
}
备注,记得#import<libkern/OSAtomic.h>