Dispatch Source Timer的使用及注意事项介绍
前言
DispatchSourceTimer是一种与DispatchQueue结合使用的定时器。当需要在后台queue中定期执行任务的时候,使用DispatchSourceTimer要比使用NSTimer更加自然,也更加高效(无需在mainqueue和后台queue之前切换)。下面将详细给大家介绍关于DispatchSourceTimer的使用和一些注意事项,话不多说了,来一起看看详细的介绍吧。
创建Timer
DispatchSourceTimer首先其实是DispatchSource的一种,关于DispatchSource的内容在这里就不再赘述了。下面是苹果官方文档里给出的创建DispatchTimer的代码:
dispatch_source_tCreateDispatchTimer(uint64_tinterval, uint64_tleeway, dispatch_queue_tqueue, dispatch_block_tblock) { dispatch_source_ttimer=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); } returntimer; }
有几个地方需要注意:
- DispatchSourceTimer是间隔定时器,也就是说每隔一段时间间隔定时器就会触发。在NSTimer中要做到同样的效果需要手动把repeats设置为YES。
- dispatch_source_set_timer中第二个参数,当我们使用dispatch_time或者DISPATCH_TIME_NOW时,系统会使用默认时钟来进行计时。然而当系统休眠的时候,默认时钟是不走的,也就会导致计时器停止。使用dispatch_walltime可以让计时器按照真实时间间隔进行计时。
- dispatch_source_set_timer的第四个参数leeway指的是一个期望的容忍时间,将它设置为1秒,意味着系统有可能在定时器时间到达的前1秒或者后1秒才真正触发定时器。在调用时推荐设置一个合理的leeway值。需要注意,就算指定leeway值为0,系统也无法保证完全精确的触发时间,只是会尽可能满足这个需求。
- eventhandlerblock中的代码会在指定的queue中执行。当queue是后台线程的时候,dispatchtimer相比NSTimer就好操作一些了。因为NSTimer是需要Runloop支持的,如果要在后台dispatchqueue中使用,则需要手动添加Runloop。使用dispatchtimer就简单很多了。
- dispatch_source_set_event_handler这个函数在执行完之后,block会立马执行一遍,后面隔一定时间间隔再执行一次。而NSTimer第一次执行是到计时器触发之后。这也是和NSTimer之间的一个显著区别。
停止Timer
停止DispatchTimer有两种方法,一种是使用dispatch_suspend,另外一种是使用dispatch_source_cancel。
dispatch_suspend严格上只是把Timer暂时挂起,它和dispatch_resume是一个平衡调用,两者分别会减少和增加dispatch对象的挂起计数。当这个计数大于0的时候,Timer就会执行。在挂起期间,产生的事件会积累起来,等到resume的时候会融合为一个事件发送。
需要注意的是:dispatchsource并没有提供用于检测source本身的挂起计数的API,也就是说外部不能得知一个source当前是不是挂起状态,在设计代码逻辑时需要考虑到这一点。
dispatch_source_cancel则是真正意义上的取消Timer。被取消之后如果想再次执行Timer,只能重新创建新的Timer。这个过程类似于对NSTimer执行invalidate。
关于取消Timer,另外一个很重要的注意事项:dispatch_suspend之后的Timer,是不能被释放的!下面的代码会引起崩溃:
-(void)stopTimer { dispatch_suspend(_timer); _timer=nil;//EXC_BAD_INSTRUCTION崩溃 }
因此使用dispatch_suspend时,Timer本身的实例需要一直保持。使用dispatch_source_cancel则没有这个限制:
-(void)stopTimer { dispatch_source_cancel(_timer); _timer=nil;//OK }
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。