我們?cè)陂_(kāi)發(fā)中可能會(huì)遇到多個(gè)網(wǎng)絡(luò)請(qǐng)求的需求鳞陨,比如一個(gè)界面有兩個(gè)請(qǐng)求,tableView的數(shù)據(jù)源及表頭瞻惋,需要等兩個(gè)請(qǐng)求都完成才刷新UI厦滤,或者第二個(gè)的網(wǎng)絡(luò)請(qǐng)求依賴(lài)第一個(gè)網(wǎng)絡(luò)請(qǐng)求返回的數(shù)據(jù),今天主要講下兩種方式的實(shí)現(xiàn)方式歼狼,當(dāng)然也有其他方式掏导,主要記錄下我工作中使用的
并發(fā)執(zhí)行
多個(gè)網(wǎng)絡(luò)請(qǐng)求同時(shí)執(zhí)行,等所有網(wǎng)絡(luò)請(qǐng)求完成羽峰,再統(tǒng)一做其他操作趟咆,你可能會(huì)想到dispatch_group_async
、dispatch_group_notify
結(jié)合使用梅屉,如下:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"任務(wù)一完成");
});
dispatch_group_async(group, queue, ^{
NSLog(@"任務(wù)二完成");
});
dispatch_group_async(group, queue, ^{
NSLog(@"任務(wù)三完成");
});
//在分組的所有任務(wù)完成后觸發(fā)
dispatch_group_notify(group, queue, ^{
NSLog(@"所有任務(wù)完成");
});
打印結(jié)果:
2017-02-17 09:26:18.668 信號(hào)量[53171:2916114] 任務(wù)二完成
2017-02-17 09:26:18.668 信號(hào)量[53171:2916133] 任務(wù)三完成
2017-02-17 09:26:18.668 信號(hào)量[53171:2916117] 任務(wù)一完成
2017-02-17 09:26:18.669 信號(hào)量[53171:2916117] 所有任務(wù)完成
由于三個(gè)任務(wù)都是異步的值纱,所有返回結(jié)果順序不一定是正序,看似卻確實(shí)實(shí)現(xiàn)了我們的需求坯汤,但是網(wǎng)絡(luò)請(qǐng)求是異步的计雌,耗時(shí)的,不是馬上就能返回結(jié)果的玫霎,如下使用dispatch_after
模擬網(wǎng)絡(luò)請(qǐng)求的延遲:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"請(qǐng)求一");
});
});
dispatch_group_async(group, queue, ^{
NSLog(@"任務(wù)二完成");
});
dispatch_group_async(group, queue, ^{
NSLog(@"任務(wù)三完成");
});
//在分組的所有任務(wù)完成后觸發(fā)
dispatch_group_notify(group, queue, ^{
NSLog(@"所有任務(wù)完成");
});
打印結(jié)果:
2017-02-17 09:30:49.263 信號(hào)量[53528:2935734] 任務(wù)二完成
2017-02-17 09:30:49.263 信號(hào)量[53528:2935737] 任務(wù)三完成
2017-02-17 09:30:49.263 信號(hào)量[53528:2935737] 所有任務(wù)完成
2017-02-17 09:30:50.340 信號(hào)量[53528:2935638] 請(qǐng)求一
可看到任務(wù)一的延遲請(qǐng)求完成造成了一些問(wèn)題凿滤,這時(shí)候我們可以用信號(hào)量即dispatch_semaphore
妈橄,包括三個(gè)部分:dispatch_semaphore_create()
、dispatch_semaphore_signal()
翁脆、dispatch_semaphore_wait()
,三個(gè)結(jié)合使用眷蚓,各個(gè)參數(shù)解釋一下:
dispatch_semaphore_create
:dispatch_semaphore_t dispatch_semaphore_create(long value)
;傳入的參數(shù)為long
類(lèi)型,輸出一個(gè)dispatch_semaphore_t
類(lèi)型且值為value
的信號(hào)量反番。值得注意的是沙热,這里的傳入的參數(shù)value必須大于或等于0
,否則dispatch_semaphore_create
會(huì)返回NULL
罢缸。
-
dispatch_semaphore_signal
的聲明為long
dispatch_semaphore_signal(dispatch_semaphore_t dsema)
篙贸,這個(gè)函數(shù)會(huì)使傳入的信號(hào)量dsema
的值加1
; - dispatch_semaphore_wait的聲明為:
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout)
枫疆;這個(gè)函數(shù)會(huì)使傳入的信號(hào)量dsema
的值減1
爵川;這個(gè)函數(shù)的作用是這樣的,如果dsema
信號(hào)量的值大于0
息楔,該函數(shù)所處線(xiàn)程就繼續(xù)執(zhí)行下面的語(yǔ)句寝贡,并且將信號(hào)量的值減1
;如果desema
的值為0
值依,那么這個(gè)函數(shù)就阻塞當(dāng)前線(xiàn)程等待timeout
(注意timeout的類(lèi)型為dispatch_time_t
圃泡,不能直接傳入整形或float型數(shù)),如果等待的期間desema
的值被dispatch_semaphore_signal
函數(shù)加1
了愿险,且該函數(shù)(即dispatch_semaphore_wait
)所處線(xiàn)程獲得了信號(hào)量颇蜡,那么就繼續(xù)向下執(zhí)行并將信號(hào)量減1
。如果等待期間沒(méi)有獲取到信號(hào)量或者信號(hào)量的值一直為0
辆亏,那么等到timeout
時(shí)澡匪,其所處線(xiàn)程自動(dòng)執(zhí)行其后語(yǔ)句。 -
dispatch_semaphore_signal
的返回值為long
類(lèi)型褒链,當(dāng)返回值為0
時(shí)表示當(dāng)前并沒(méi)有線(xiàn)程等待其處理的信號(hào)量,其處理的信號(hào)量的值加1
即可疑苔。當(dāng)返回值不為0
時(shí)甫匹,表示其當(dāng)前有(一個(gè)或多個(gè))線(xiàn)程等待其處理的信號(hào)量,并且該函數(shù)喚醒了一個(gè)等待的線(xiàn)程(當(dāng)線(xiàn)程有優(yōu)先級(jí)時(shí)惦费,喚醒優(yōu)先級(jí)最高的線(xiàn)程兵迅;否則隨機(jī)喚醒)。dispatch_semaphore_wait
的返回值也為long
型薪贫。當(dāng)其返回0
時(shí)表示在timeout
之前恍箭,該函數(shù)所處的線(xiàn)程被成功喚醒。當(dāng)其返回不為0
時(shí)瞧省,表示timeout
發(fā)生扯夭。 - 在設(shè)置
timeout
時(shí)鳍贾,比較有用的兩個(gè)宏:DISPATCH_TIME_NOW
和DISPATCH_TIME_FOREVER
。DISPATCH_TIME_NOW
表示當(dāng)前交洗;DISPATCH_TIME_FOREVER
表示遙遠(yuǎn)的未來(lái)骑科;一般可以直接設(shè)置timeout
為這兩個(gè)宏其中的一個(gè),或者自己創(chuàng)建一個(gè)dispatch_time_t
類(lèi)型的變量构拳。創(chuàng)建dispatch_time_t
類(lèi)型的變量有兩種方法咆爽,dispatch_time
和dispatch_walltime
。利用創(chuàng)建dispatch_time
創(chuàng)建dispatch_time_t
類(lèi)型變量的時(shí)候一般也會(huì)用到這兩個(gè)變量dispatch_time
的聲明如下:dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta)
置森;其參數(shù)when需傳入一個(gè)dispatch_time_t
類(lèi)型的變量斗埂,和一個(gè)delta
值。表示when
加delta
時(shí)間就是timeout
的時(shí)間凫海。例如:dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW, 1*1000*1000*1000)
;表示當(dāng)前時(shí)間向后延時(shí)一秒為timeout
的時(shí)間呛凶。 - 關(guān)于信號(hào)量,一般可以用停車(chē)來(lái)比喻:
停車(chē)場(chǎng)剩余4個(gè)車(chē)位盐碱,那么即使同時(shí)來(lái)了四輛車(chē)也能停的下把兔。如果此時(shí)來(lái)了五輛車(chē),那么就有一輛需要等待瓮顽。信號(hào)量的值就相當(dāng)于剩余車(chē)位的數(shù)目县好,dispatch_semaphore_wait
函數(shù)就相當(dāng)于來(lái)了一輛車(chē),dispatch_semaphore_signal
就相當(dāng)于走了一輛車(chē)暖混。停車(chē)位的剩余數(shù)目在初始化的時(shí)候就已經(jīng)指明了(dispatch_semaphore_create(long value)
)缕贡,調(diào)用一次dispatch_semaphore_signal
,剩余的車(chē)位就增加一個(gè)拣播;調(diào)用一次dispatch_semaphore_wait
剩余車(chē)位就減少一個(gè)晾咪;當(dāng)剩余車(chē)位為0時(shí),再來(lái)車(chē)(即調(diào)用dispatch_semaphore_wait
)就只能等待贮配。有可能同時(shí)有幾輛車(chē)等待一個(gè)停車(chē)位谍倦。有些車(chē)主沒(méi)有耐心,給自己設(shè)定了一段等待時(shí)間泪勒,這段時(shí)間內(nèi)等不到停車(chē)位就走了昼蛀,如果等到了就開(kāi)進(jìn)去停車(chē)。而有些車(chē)主就像把車(chē)停在這圆存,所以就一直等下去叼旋。
代碼示例:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
dispatch_group_async(group, queue, ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_semaphore_signal(sem);
NSLog(@"請(qǐng)求一");
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
});
dispatch_group_async(group, queue, ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_semaphore_signal(sem);
NSLog(@"請(qǐng)求二");
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
});
dispatch_group_async(group, queue, ^{
NSLog(@"請(qǐng)求三");
});
//在分組的所有任務(wù)完成后觸發(fā)
dispatch_group_notify(group, queue, ^{
NSLog(@"請(qǐng)求完成");
});
打印結(jié)果:
2017-02-17 09:47:58.084 信號(hào)量[54431:3002639] 請(qǐng)求三
2017-02-17 09:47:58.958 信號(hào)量[54431:3002590] 請(qǐng)求二
2017-02-17 09:47:59.177 信號(hào)量[54431:3002590] 請(qǐng)求一
2017-02-17 09:47:59.177 信號(hào)量[54431:3002636] 請(qǐng)求完成
就實(shí)現(xiàn)了我們的需求(多個(gè)網(wǎng)絡(luò)請(qǐng)求都完成再做其他操作),當(dāng)然也可以通過(guò)dispatch_group_enter、dispatch_group_leave
結(jié)合實(shí)現(xiàn)沦辙,使用dispatch_group_enter()
函數(shù)進(jìn)入到任務(wù)組中夫植,然后異步執(zhí)行隊(duì)列中的任務(wù),最后使用dispatch_group_leave()
函數(shù)離開(kāi)任務(wù)組即可油讯,
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任務(wù)1");
dispatch_group_leave(group);
});
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"任務(wù)2");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"任務(wù)3");
dispatch_group_leave(group);
});
dispatch_group_notify(group, queue, ^{
NSLog(@"完成");
});
打印結(jié)果:
2017-02-17 09:56:13.129 信號(hào)量[54888:3036359] 任務(wù)2
2017-02-17 09:56:13.129 信號(hào)量[54888:3036359] 任務(wù)3
2017-02-17 09:56:14.222 信號(hào)量[54888:3036264] 任務(wù)1
2017-02-17 09:56:14.222 信號(hào)量[54888:3036359] 完成
同樣實(shí)現(xiàn)了我們需求
順序執(zhí)行
仍然通過(guò)信號(hào)量執(zhí)行详民,執(zhí)行任務(wù)一延欠,將信號(hào)量dispatch_semaphore_wait
減一,請(qǐng)求完成阐斜,再dispatch_semaphore_signal
加一衫冻,一次類(lèi)推,代碼實(shí)現(xiàn)
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
dispatch_queue_t queue = dispatch_queue_create("testBlock", NULL);
dispatch_async(queue, ^{
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"1");
dispatch_semaphore_signal(sem);
});
});
dispatch_async(queue, ^{
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
NSLog(@"2");
dispatch_semaphore_signal(sem);
});
dispatch_async(queue, ^{
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"3");
dispatch_semaphore_signal(sem);
});
});
dispatch_async(queue, ^{
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
NSLog(@"4");
dispatch_semaphore_signal(sem);
});
打印結(jié)果:
2017-02-17 09:57:54.058 信號(hào)量[54991:3043275] 1
2017-02-17 09:57:54.059 信號(hào)量[54991:3043355] 2
2017-02-17 09:57:57.358 信號(hào)量[54991:3043275] 3
2017-02-17 09:57:57.358 信號(hào)量[54991:3043355] 4
這篇文章對(duì)信號(hào)量做了詳細(xì)介紹
參考:
關(guān)于dispatch_semaphore的使用