Dispatch Source的自定義事件

使用 Dispatch Source 而不使用 dispatch_async 的唯一原因就是利用聯(lián)結(jié)的優(yōu)勢(shì)。

聯(lián)結(jié)的大致流程:在任一線程上調(diào)用它的一個(gè)函數(shù) dispatch_source_merge_data 后帝牡,會(huì)在相應(yīng)quene執(zhí)行 Dispatch Source 事先定義好的句柄(可以把句柄簡(jiǎn)單理解為一個(gè) block )巍耗。

這個(gè)過(guò)程叫 Custom event 抓歼,用戶事件嚷闭。是 dispatch source 支持處理的一種事件勤众。

簡(jiǎn)單地說(shuō)掩浙,這種事件是由你調(diào)用 dispatch_source_merge_data 函數(shù)來(lái)向自己發(fā)出的信號(hào)花吟。

一、創(chuàng)建dispatch源

dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());
參數(shù):
參數(shù) 意義
type dispatch源可處理的事件類型
handle 可以理解為索引厨姚、id或句柄衅澈,假如要監(jiān)聽(tīng)進(jìn)程,需要傳入進(jìn)程的ID
mask 可以理解為描述遣蚀,提供更詳細(xì)的描述矾麻,讓它知道具體要監(jiān)聽(tīng)什么
queue 自定義源需要的一個(gè)隊(duì)列纱耻,用來(lái)處理所有的響應(yīng)句柄(block)
Dispatch Source可處理的所有事件:
名稱 意義
DISPATCH_SOURCE_TYPE_DATA_ADD 自定義的事件,變量增加
DISPATCH_SOURCE_TYPE_DATA_OR 自定義的事件险耀,變量OR
DISPATCH_SOURCE_TYPE_MACH_SEND MACH端口發(fā)送
DISPATCH_SOURCE_TYPE_MACH_RECV MACH端口接收
DISPATCH_SOURCE_TYPE_PROC 進(jìn)程監(jiān)聽(tīng),如進(jìn)程的退出弄喘、創(chuàng)建一個(gè)或更多的子線程、進(jìn)程收到UNIX信號(hào)
DISPATCH_SOURCE_TYPE_READ IO操作甩牺,如對(duì)文件的操作蘑志、socket操作的讀響應(yīng)
DISPATCH_SOURCE_TYPE_SIGNAL 接收到UNIX信號(hào)時(shí)響應(yīng)
DISPATCH_SOURCE_TYPE_TIMER 定時(shí)器
DISPATCH_SOURCE_TYPE_VNODE 文件狀態(tài)監(jiān)聽(tīng),文件被刪除贬派、移動(dòng)急但、重命名
DISPATCH_SOURCE_TYPE_WRITE IO操作,如對(duì)文件的操作搞乏、socket操作的寫響應(yīng)

自定義事件可以使用的只有DISPATCH_SOURCE_TYPE_DATA_ADDDISPATCH_SOURCE_TYPE_DATA_OR這兩種類型波桩,我們這里也只討論這兩種類型。

二请敦、其他函數(shù):

dispatch_suspend(queue) //掛起隊(duì)列

dispatch_resume(source) //分派源創(chuàng)建時(shí)默認(rèn)處于掛起狀態(tài)镐躲,在分派源分派處理程序之前必須先恢復(fù)

dispatch_source_merge_data(source, 1) //向分派源發(fā)送事件,需要注意的是侍筛,不可以傳遞0值(事件不會(huì)被觸發(fā))萤皂,同樣也不可以傳遞負(fù)數(shù)。

dispatch_source_set_event_handler(source, block) //設(shè)置響應(yīng)分派源事件的block匣椰,在分派源指定的隊(duì)列上運(yùn)行

dispatch_source_get_data(source) //得到分派源的數(shù)據(jù)

三裆熙、代碼:

//創(chuàng)建source,以DISPATCH_SOURCE_TYPE_DATA_ADD的方式進(jìn)行累加禽笑,而DISPATCH_SOURCE_TYPE_DATA_OR是對(duì)結(jié)果進(jìn)行二進(jìn)制或運(yùn)算
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());

//設(shè)置事件觸發(fā)后執(zhí)行的句柄
dispatch_source_set_event_handler(source,^{
    NSLog(@"監(jiān)聽(tīng)函數(shù):%lu",dispatch_source_get_data(source));
});

//開(kāi)啟source
dispatch_resume(source);

dispatch_queue_t myqueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(myqueue, ^ {
    
    for(int i = 1; i <= 4; i ++){
        
        NSLog(@"~~~~~~~~~~~~~~%d", i);
        
        //異步線程觸發(fā)事件入录,向source發(fā)送事件,這里i不能為0佳镜,否則觸發(fā)不了事件
        dispatch_source_merge_data(source,i);
        
        //當(dāng)Interval的事件越長(zhǎng)纷跛,則每次的句柄都會(huì)觸發(fā)
        //[NSThread sleepForTimeInterval:1.0];
    }
});

上面的這個(gè)例子,因?yàn)閒or循環(huán)運(yùn)算速度非逞樱快,系統(tǒng)會(huì)自動(dòng)把這4次事件聯(lián)結(jié)起來(lái)唬血,可以看到最終事件觸發(fā)的句柄只會(huì)執(zhí)行一次望蜡。打印出來(lái)的結(jié)果為:

~~~~~~~~~~~~~~1
~~~~~~~~~~~~~~2
~~~~~~~~~~~~~~3
~~~~~~~~~~~~~~4
監(jiān)聽(tīng)函數(shù):10

這里的10就是把每次的事件值i相加得到的(1+2+3+4)。這里如果把DISPATCH_SOURCE_TYPE_DATA_ADD替換為DISPATCH_SOURCE_TYPE_DATA_OR拷恨,結(jié)果會(huì)是7脖律,也就是把每次的事件值i或運(yùn)算得到(1|2|3|4)。

如果把[NSThread sleepForTimeInterval:1.0]的注釋打開(kāi)腕侄,因?yàn)槭录g隔太長(zhǎng)小泉,系統(tǒng)不會(huì)聯(lián)結(jié)芦疏,此時(shí)類似于dispatch_async(),打印結(jié)果如下:

~~~~~~~~~~~~~~1
監(jiān)聽(tīng)函數(shù):1
~~~~~~~~~~~~~~2
監(jiān)聽(tīng)函數(shù):2
~~~~~~~~~~~~~~3
監(jiān)聽(tīng)函數(shù):3
~~~~~~~~~~~~~~4
監(jiān)聽(tīng)函數(shù):4

此時(shí)不論type是DISPATCH_SOURCE_TYPE_DATA_ADDDISPATCH_SOURCE_TYPE_DATA_OR微姊,結(jié)果都是這個(gè)酸茴,因?yàn)檫@兩種type只影響聯(lián)結(jié)時(shí)的value。對(duì)非聯(lián)結(jié)的情況沒(méi)有影響兢交。

四薪捍、例子:

當(dāng)我們更新進(jìn)度條時(shí),可能在多個(gè)線程上同時(shí)做很多任務(wù)配喳,每個(gè)任務(wù)完成后酪穿,刷新界面,更新一點(diǎn)進(jìn)度條的進(jìn)度晴裹,因?yàn)槊總€(gè)任務(wù)都更新一次進(jìn)度條被济,造成界面刷新次數(shù)太多,可能會(huì)導(dǎo)致界面卡頓涧团,所以此時(shí)利用Dispatch Source能很好的解決這種情況只磷,因?yàn)镈ispatch Source在刷新太頻繁的時(shí)候會(huì)自動(dòng)聯(lián)結(jié)起來(lái),下面就用代碼實(shí)現(xiàn)一下這個(gè)場(chǎng)景少欺。

//1喳瓣、指定DISPATCH_SOURCE_TYPE_DATA_ADD,做成Dispatch Source(分派源)赞别。設(shè)定Main Dispatch Queue 為追加處理的Dispatch Queue
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());

__block NSUInteger totalComplete = 0;

dispatch_source_set_event_handler(source, ^{
    //當(dāng)處理事件被最終執(zhí)行時(shí)畏陕,計(jì)算后的數(shù)據(jù)可以通過(guò)dispatch_source_get_data來(lái)獲取。這個(gè)數(shù)據(jù)的值在每次響應(yīng)事件執(zhí)行后會(huì)被重置仿滔,所以totalComplete的值是最終累積的值惠毁。
    NSUInteger value = dispatch_source_get_data(source);
    totalComplete += value;
    NSLog(@"進(jìn)度:%@", @((CGFloat)totalComplete/100));
});

//分派源創(chuàng)建時(shí)默認(rèn)處于暫停狀態(tài),在分派源分派處理程序之前必須先恢復(fù)崎页。
dispatch_resume(source);

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSUInteger index = 0; index < 100; index++) {
    dispatch_async(queue, ^{
        usleep(20000);//0.02秒
        dispatch_source_merge_data(source, 1);
    });
}

上面相等于啟動(dòng)了100個(gè)任務(wù)鞠绰,每個(gè)任務(wù)耗時(shí)0.02秒,打印結(jié)果如下:

進(jìn)度:0.25
進(jìn)度:0.32
進(jìn)度:0.37
進(jìn)度:0.41
進(jìn)度:0.55
進(jìn)度:0.61
進(jìn)度:0.63
進(jìn)度:0.64
進(jìn)度:0.76
進(jìn)度:0.89
進(jìn)度:0.96
進(jìn)度:1

附上demo飒焦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蜈膨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子牺荠,更是在濱河造成了極大的恐慌翁巍,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡喳坠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門驰凛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)胸懈,“玉大人,你說(shuō)我怎么就攤上這事恰响∪で” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵渔隶,是天一觀的道長(zhǎng)羔挡。 經(jīng)常有香客問(wèn)我,道長(zhǎng)间唉,這世上最難降的妖魔是什么绞灼? 我笑而不...
    開(kāi)封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮呈野,結(jié)果婚禮上低矮,老公的妹妹穿的比我還像新娘。我一直安慰自己被冒,他們只是感情好军掂,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著昨悼,像睡著了一般蝗锥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上率触,一...
    開(kāi)封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天终议,我揣著相機(jī)與錄音,去河邊找鬼葱蝗。 笑死穴张,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的两曼。 我是一名探鬼主播皂甘,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼悼凑!你這毒婦竟也來(lái)了偿枕?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤户辫,失蹤者是張志新(化名)和其女友劉穎益老,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體寸莫,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年档冬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了膘茎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桃纯。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖披坏,靈堂內(nèi)的尸體忽然破棺而出态坦,到底是詐尸還是另有隱情,我是刑警寧澤棒拂,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布伞梯,位于F島的核電站,受9級(jí)特大地震影響帚屉,放射性物質(zhì)發(fā)生泄漏谜诫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一攻旦、第九天 我趴在偏房一處隱蔽的房頂上張望喻旷。 院中可真熱鬧,春花似錦牢屋、人聲如沸且预。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锋谐。三九已至,卻和暖如春截酷,著一層夾襖步出監(jiān)牢的瞬間涮拗,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工合搅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留多搀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓灾部,卻偏偏與公主長(zhǎng)得像康铭,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赌髓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容