dispatch timer就是一類(lèi)dispatch source:DISPATCH_SOURCE_TYPE_TIMER,并非是一個(gè)單獨(dú)的timer。還有DISPATCH_SOURCE_TYPE_DATA_ADD等共10類(lèi)。這10類(lèi)作用基本都是監(jiān)聽(tīng)事件。只是用法不同,timer是固定時(shí)間觸發(fā)監(jiān)聽(tīng)事件。
DISPATCH_SOURCE_TYPE_DATA_ADD類(lèi)型的源是在調(diào)用dispatch_source_merge_data的時(shí)候觸發(fā)事件,而且它有個(gè)很有意思的特點(diǎn)就是當(dāng)同一時(shí)間,一個(gè)事件的的觸發(fā)頻率很高時(shí),Dispatch Source會(huì)將這些事件以ADD的方式進(jìn)行累積,然后等系統(tǒng)空閑時(shí)最終處理。如果觸發(fā)頻率比較零散,那么Dispatch Source會(huì)將這些事件分別響應(yīng)。
而且這些源都基本的操作都是:1. 創(chuàng)建;2. 分發(fā);3. 掛起;4,取消。
下面開(kāi)始詳細(xì)看下dispatch timer的使用。
創(chuàng)建timer
創(chuàng)建timer的代碼如下:
// 創(chuàng)建timer
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 開(kāi)始時(shí)間
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, 1.0*NSEC_PER_SEC);
// 間隔時(shí)間
dispatch_time_t interval = 2.0*NSEC_PER_SEC;
dispatch_source_set_timer(timer,start,interval,1000ull);
注意,在ARC中dispatch_source_t和普通的OC對(duì)象一樣使用,所以timer使用時(shí)不要是局部變量,因?yàn)榫植孔兞繒?huì)立即釋放。要注意timer的生命周期,這個(gè)和NSTimer一樣。需要注意的是dispatch timer中用到的時(shí)間都是納秒,即NSEC_PER_SEC。這里要注意的是dispatch timer沒(méi)有repect參數(shù),如果只想觸發(fā)一次需要把間隔時(shí)間設(shè)置成DISPATCH_TIME_FOREVER。
事件處理
dispatch timer的處理分為兩種:block和函數(shù)指針;
// block形式
dispatch_source_set_event_handler(timer, ^{
// 這里是一個(gè)無(wú)參數(shù)無(wú)返回值的block
});
上面是block形式,使用時(shí)也要注意循環(huán)引用。這個(gè)和NSTimer是一樣的。仔細(xì)看方法名可以注意到,該方法名與timer是沒(méi)關(guān)系的,也就是其他類(lèi)型的源想要設(shè)置handler也是這樣的。
// 設(shè)置跟隨timer的context
void *context = NULL;
dispacth_set_context(timer,context);
// C類(lèi)型的回調(diào)方法
void funcPointer1(void*arg){//...}
void funcPointer2(void*arg){//...}
// 設(shè)置回調(diào)方法
dispach_source_set_event_handler_f(timer,funcPointer1);
dispach_source_set_cancel_event_handler_f(timer,funcPointer2);
上面是函數(shù)指針的形式。要比block復(fù)雜一點(diǎn)。從下往上看,可以看到可以設(shè)置兩個(gè)回調(diào)方法,分別是事件觸發(fā)和事件取消時(shí)的方法?;卣{(diào)方法是一個(gè)C的函數(shù)指針。函數(shù)指針類(lèi)型如funcPointer1所示。跟隨timer的context是block沒(méi)有的重要的功能。該context會(huì)在事件觸發(fā)時(shí)傳遞給funcPointer1方法。context是一個(gè)void*的指針,可以添加任意多的內(nèi)容。但是注意的是在ARC下結(jié)構(gòu)體內(nèi)部不能有對(duì)象。注意context可能會(huì)造成循環(huán)引用。
分發(fā)事件與停止事件
事件分發(fā)和事件觸發(fā)在這是兩個(gè)完全不同的事。比如timer的事件觸發(fā)是底層mk_timer觸發(fā)的。事件觸發(fā)后能不能分發(fā)是由GCD決定的。再比如DISPATCH_SOURCE_TYPE_DATA_ADD是我們調(diào)用dispatch_source_merge_data觸發(fā)的,能不能分發(fā)也是有GCD決定的。
// 啟動(dòng)分發(fā)事件
dispatch_resume(source);
// 暫停分發(fā)事件
dispacth_suspend(source);
// 取消事件,也就是停止監(jiān)聽(tīng)事件
dispatch_cancel(source);
dispatch_resume事件想要被處理就必須調(diào)用該方法,該方法可以理解成是事件分發(fā)的開(kāi)關(guān)。dispatch_suspend會(huì)暫停事件分發(fā)。暫停期間,所有的事件都會(huì)被丟棄,也就是在此開(kāi)始時(shí)這期間的事件不會(huì)被處理。dispatch_cancel會(huì)停止接收時(shí)間,無(wú)法再開(kāi)始。如果強(qiáng)行掉resumen會(huì)crash!