大家在開(kāi)發(fā)的過(guò)程中,經(jīng)常會(huì)用到定時(shí)器,通常的做法可能就是NSTimer,了解過(guò)GCD的同學(xué)可能會(huì)接觸到dispatch source的概念,dispatch source是一個(gè)監(jiān)視某些類型事件的對(duì)象。當(dāng)這些事件發(fā)生時(shí),它自動(dòng)將一個(gè)block放入一個(gè)dispatch queue的執(zhí)行例程中。
dispatch source支持的事件有很多,__MAC_10_6支持的事件如下:(請(qǐng)參考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)
這里主要說(shuō)一下計(jì)時(shí)器,對(duì)其他事件感興趣的同學(xué)可以網(wǎng)上查些資料。
GCD計(jì)時(shí)器的使用通常由一下幾個(gè)函數(shù)構(gòu)成:
1.dispatch_source_create
創(chuàng)建一個(gè)新的調(diào)度源來(lái)監(jiān)視低級(jí)別的系統(tǒng)對(duì)象和自動(dòng)提交處理程序塊來(lái)響應(yīng)事件調(diào)度隊(duì)列
2.dispatch_source_set_timer
為一個(gè)定時(shí)源設(shè)置一個(gè)開(kāi)始時(shí)間、事件間隔、誤差值
我們來(lái)看看這個(gè)函數(shù)原型
dispatch_source_set_timer(dispatch_source_t source,
dispatch_time_t start,
uint64_t interval,
uint64_t leeway);
source當(dāng)然就是我們第一步創(chuàng)建的調(diào)度源。
start是我們?cè)O(shè)定的計(jì)時(shí)開(kāi)始時(shí)間,可以dispatch_time 和 dispatch_walltime 函數(shù)來(lái)創(chuàng)建它們,至于dispatch_time跟dispatch_walltime的區(qū)別,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上測(cè)試的時(shí)候好像并沒(méi)有什么卵用,難道是Mac跟iPhone的機(jī)制不一樣?有興趣的同學(xué)可以去深究一下,找到答案可以告訴我一下。
interval就是時(shí)間間隔了,這個(gè)不用多說(shuō)了。
leeway,對(duì)這個(gè)參數(shù)的理解,我覺(jué)得http://www.dreamingwish.com上Seven's同學(xué)的解釋很直觀也很易懂:
“這個(gè)參數(shù)告訴系統(tǒng)我們需要計(jì)時(shí)器觸發(fā)的精準(zhǔn)程度。所有的計(jì)時(shí)器都不會(huì)保證100%精準(zhǔn),這個(gè)參數(shù)用來(lái)告訴系統(tǒng)你希望系統(tǒng)保證精準(zhǔn)的努力程度。如果你希望一個(gè)計(jì)時(shí)器沒(méi)五秒觸發(fā)一次,并且越準(zhǔn)越好,那么你傳遞0為參數(shù)。另外,如果是一個(gè)周期性任務(wù),比如檢查email,那么你會(huì)希望每十分鐘檢查一次,但是不用那么精準(zhǔn)。所以你可以傳入60,告訴系統(tǒng)60秒的誤差是可接受的。這樣有什么意義呢?簡(jiǎn)單來(lái)說(shuō),就是降低資源消耗。如果系統(tǒng)可以讓cpu休息足夠長(zhǎng)的時(shí)間,并在每次醒來(lái)的時(shí)候執(zhí)行一個(gè)任務(wù)集合,而不是不斷的醒來(lái)睡去以執(zhí)行任務(wù),那么系統(tǒng)會(huì)更高效。如果傳入一個(gè)比較大的leeway給你的計(jì)時(shí)器,意味著你允許系統(tǒng)拖延你的計(jì)時(shí)器來(lái)將計(jì)時(shí)器任務(wù)與其他任務(wù)聯(lián)合起來(lái)一起執(zhí)行?!?/p>
3.dispatch_source_set_event_handler
給一個(gè)調(diào)度源設(shè)置一個(gè)時(shí)間處理塊。
4.dispatch_source_cancel
異步取消一個(gè)調(diào)度源,防止任何進(jìn)一步調(diào)用它的事件處理塊的發(fā)生
5.dispatch_source_set_cancel_handler
給一個(gè)調(diào)度源設(shè)置一個(gè)取消處理塊
6.dispatch_resume
同步等待一個(gè)對(duì)象,直到超時(shí)
以上幾個(gè)步驟中,dispatch_source_set_event_handler與dispatch_source_cancel必須一起出現(xiàn),否則調(diào)度源處理塊不會(huì)執(zhí)行。
下面附一段完整的代碼,演示一個(gè)簡(jiǎn)單的10秒倒計(jì)時(shí)的功能:
- (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>