Dispatch Source Timer的使用及注意事項(xiàng)介紹

前言
Dispatch Source Timer 是一種與 Dispatch Queue 結(jié)合使用的定時(shí)器。當(dāng)需要在后臺(tái) queue 中定期執(zhí)行任務(wù)的時(shí)候,使用 Dispatch Source Timer 要比使用 NSTimer 更加自然,也更加高效(無(wú)需在 main queue 和后臺(tái) queue 之前切換)。下面將詳細(xì)給大家介紹關(guān)于Dispatch Source Timer的使用和一些注意事項(xiàng),話(huà)不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧。
創(chuàng)建 Timer
Dispatch Source Timer 首先其實(shí)是 Dispatch Source 的一種,關(guān)于 Dispatch Source 的內(nèi)容在這里就不再贅述了。下面是蘋(píng)果官方文檔里給出的創(chuàng)建 Dispatch Timer 的代碼:

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;
}

有幾個(gè)地方需要注意:
Dispatch Source Timer 是間隔定時(shí)器,也就是說(shuō)每隔一段時(shí)間間隔定時(shí)器就會(huì)觸發(fā)。在 NSTimer 中要做到同樣的效果需要手動(dòng)把 repeats 設(shè)置為 YES。
dispatch_source_set_timer 中第二個(gè)參數(shù),當(dāng)我們使用dispatch_time 或者 DISPATCH_TIME_NOW 時(shí),系統(tǒng)會(huì)使用默認(rèn)時(shí)鐘來(lái)進(jìn)行計(jì)時(shí)。然而當(dāng)系統(tǒng)休眠的時(shí)候,默認(rèn)時(shí)鐘是不走的,也就會(huì)導(dǎo)致計(jì)時(shí)器停止。使用 dispatch_walltime 可以讓計(jì)時(shí)器按照真實(shí)時(shí)間間隔進(jìn)行計(jì)時(shí)。
dispatch_source_set_timer 的第四個(gè)參數(shù) leeway 指的是一個(gè)期望的容忍時(shí)間,將它設(shè)置為 1 秒,意味著系統(tǒng)有可能在定時(shí)器時(shí)間到達(dá)的前 1 秒或者后 1 秒才真正觸發(fā)定時(shí)器。在調(diào)用時(shí)推薦設(shè)置一個(gè)合理的 leeway 值。需要注意,就算指定 leeway 值為 0,系統(tǒng)也無(wú)法保證完全精確的觸發(fā)時(shí)間,只是會(huì)盡可能滿(mǎn)足這個(gè)需求。
event handler block 中的代碼會(huì)在指定的 queue 中執(zhí)行。當(dāng) queue 是后臺(tái)線程的時(shí)候,dispatch timer 相比 NSTimer 就好操作一些了。因?yàn)?NSTimer 是需要 Runloop 支持的,如果要在后臺(tái) dispatch queue 中使用,則需要手動(dòng)添加 Runloop。使用 dispatch timer 就簡(jiǎn)單很多了。
dispatch_source_set_event_handler 這個(gè)函數(shù)在執(zhí)行完之后,block 會(huì)立馬執(zhí)行一遍,后面隔一定時(shí)間間隔再執(zhí)行一次。而 NSTimer 第一次執(zhí)行是到計(jì)時(shí)器觸發(fā)之后。這也是和 NSTimer 之間的一個(gè)顯著區(qū)別。
停止 Timer
停止 Dispatch Timer 有兩種方法,一種是使用 dispatch_suspend,另外一種是使用 dispatch_source_cancel。
dispatch_suspend 嚴(yán)格上只是把 Timer 暫時(shí)掛起,它和 dispatch_resume 是一個(gè)平衡調(diào)用,兩者分別會(huì)減少和增加 dispatch 對(duì)象的掛起計(jì)數(shù)。當(dāng)這個(gè)計(jì)數(shù)大于 0 的時(shí)候,Timer 就會(huì)執(zhí)行。在掛起期間,產(chǎn)生的事件會(huì)積累起來(lái),等到 resume 的時(shí)候會(huì)融合為一個(gè)事件發(fā)送。
需要注意的是:dispatch source 并沒(méi)有提供用于檢測(cè) source 本身的掛起計(jì)數(shù)的 API,也就是說(shuō)外部不能得知一個(gè) source 當(dāng)前是不是掛起狀態(tài),在設(shè)計(jì)代碼邏輯時(shí)需要考慮到這一點(diǎn)。
dispatch_source_cancel 則是真正意義上的取消 Timer。被取消之后如果想再次執(zhí)行 Timer,只能重新創(chuàng)建新的 Timer。這個(gè)過(guò)程類(lèi)似于對(duì) NSTimer 執(zhí)行 invalidate。
關(guān)于取消 Timer,另外一個(gè)很重要的注意事項(xiàng):dispatch_suspend 之后的 Timer,是不能被釋放的!下面的代碼會(huì)引起崩潰:

- (void)stopTimer
{
 dispatch_suspend(_timer);
 _timer = nil; // EXC_BAD_INSTRUCTION 崩潰
}

因此使用 dispatch_suspend 時(shí),Timer 本身的實(shí)例需要一直保持。使用 dispatch_source_cancel 則沒(méi)有這個(gè)限制:

- (void)stopTimer
{
 dispatch_source_cancel(_timer);
 _timer = nil; // OK
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容