
內(nèi)容結(jié)構(gòu)框圖.png
1.GCD基本概念
GCD2個(gè)核心的概念
任務(wù):執(zhí)行什么操作
隊(duì)列:用來存放任務(wù)
GCD使用
(1)定制任務(wù)
(2)確定想做的事情
將任務(wù)添加到隊(duì)列中,GCD會自動的將隊(duì)列中的任務(wù)取出,放到對應(yīng)的線程中執(zhí)行
注意:任務(wù)的取出遵循先進(jìn)先出,后進(jìn)后出的原則。
GCD執(zhí)行任務(wù)函數(shù)
(1)同步方式執(zhí)行任務(wù)
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
參數(shù)說明:queue: 隊(duì)列
block: 任務(wù)
理解: 把右邊的任務(wù)(block)放到左邊的隊(duì)列(queue)中執(zhí)行
(2)異步方式執(zhí)行任務(wù)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
同步,異步的區(qū)別
同步:在當(dāng)前線程中執(zhí)行
異步:在另一條線程中執(zhí)行
串行,并發(fā)的區(qū)別
串行:一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù)
并發(fā):多個(gè)任務(wù)并發(fā)同時(shí)執(zhí)行
1.獲取串行隊(duì)列
方式1:使用dispatch_queue_create創(chuàng)建串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("laowang", NULL);
方式2:使用主隊(duì)列 (和主線程相關(guān)的隊(duì)列)
主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列,放在主隊(duì)列中的任務(wù),都會放在主線程中執(zhí)行
dispatch_queue_t queue = dispatch_get_main_queue();
2.獲取并發(fā)隊(duì)列
方式1:使用dispatch_queue_create創(chuàng)建并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_queue_create(“l(fā)aowang”,
DISPATCH_QUEUE_CONCURRENT);
方式2:GCD默認(rèn)提供全局并發(fā)隊(duì)列,供整個(gè)應(yīng)用使用,不需要手動創(chuàng)建
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
各種隊(duì)列執(zhí)行效果
串行隊(duì)列為使用dispatch_queue_create 創(chuàng)建的串行隊(duì)列
異步并發(fā):
開啟新的線程,并發(fā)執(zhí)行
異步串行:
開啟新的線程,串行執(zhí)行
同步并發(fā):
不開啟新的線程,串行執(zhí)行任務(wù)
同步串行:
不開啟新的線程,串行執(zhí)行任務(wù)
隊(duì)列,任務(wù)總結(jié)
1.同步函數(shù)不具備開啟線程的能力,無論什么隊(duì)列都不會開始線程。
2.異步函數(shù)具備開啟線程的能力,開啟線程的條數(shù)由隊(duì)列決定。(串行隊(duì)列為1條,并行隊(duì)列為多條)
異步函數(shù)具備開線程的能力,但是不一定會開啟線程。
2.dispatch_group(調(diào)度組)
調(diào)度組最重要的目的,監(jiān)聽一組任務(wù)完成
如果想在dispatch_queue中所有的任務(wù)執(zhí)行完成后在做某種操作,在串行隊(duì)列中,可以把該操作放到最后一個(gè)任務(wù)執(zhí)行完成后繼續(xù),但是在并行隊(duì)列中怎么做呢。這就有dispatch_group 成組操作。
dispatch_group 使用函數(shù)
1.dispatch_group_async
dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue,dispatch_block_t block);
將任務(wù)(block)放入隊(duì)列queue,然后和調(diào)度組group關(guān)聯(lián)
dispatch_queue_t dispatchQueue = dispatch_queue_create("laowang", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t dispatchGroup = dispatch_group_create();
dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
NSLog(@"dispatch-1");
});
dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
NSLog(@"dspatch-2");
});
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){
NSLog(@"end");
});
上面的 log1 和log2輸出順序不定,因?yàn)槭窃诓l(fā)隊(duì)列上執(zhí)行,當(dāng)并發(fā)隊(duì)列全部執(zhí)行完成后,最后到main隊(duì)列上執(zhí)行一個(gè)操作,保證“end”是最后輸出。
2.dispatch_group_enter(group) dispatch_group_leave(group)
標(biāo)志著一個(gè)block(任務(wù))被加入了group。
dispatch_group_enter:增加當(dāng)前group執(zhí)行block數(shù)
dispatch_group_leave:減少當(dāng)前group執(zhí)行block數(shù)
調(diào)用dispatch_group_enter,dispatch_group_leave 可以非常適合處理異步任務(wù)同步(當(dāng)有多個(gè)異步請求時(shí),需要等待異步請求都結(jié)束時(shí)做些事情),當(dāng)異步任務(wù)開始前調(diào)用dispatch_group_enter,異步任務(wù)結(jié)束后調(diào)用dispatch_group_leave
例:
dispatch_group_t group = dispatch_group_create();
//1.任務(wù)開始調(diào)用enter
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(5);
NSLog(@"任務(wù)一完成");
//2.任務(wù)結(jié)束調(diào)用leave
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任務(wù)二完成");
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"任務(wù)完成");
});
注意
假如我們不想使用dispatch_group_async異步的將任務(wù)丟到group中去執(zhí)行,這時(shí)候就需要用到dispatch_group_enter跟dispatch_group_leave方法,這兩個(gè)方法要配對出現(xiàn),以下這兩種方法是等價(jià)的:
dispatch_group_async(group, queue, ^{
任務(wù)
});
等價(jià)于:
dispatch_group_enter(group);
dispatch_async(queue, ^{
//任務(wù)
dispatch_group_leave(group);
});
3種情況:
1.調(diào)度組沒有任務(wù),直接執(zhí)行notify
2.調(diào)度組入組多余出組,notify永遠(yuǎn)不會執(zhí)行,因?yàn)榻M永遠(yuǎn)不會為空
3.出租多余入組,會奔潰
3.dispatch_group_notify
void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,
dispatch_block_t block);
當(dāng)group上所有的任務(wù)被執(zhí)行完畢以后,就會調(diào)用 dispatch_group_notify
4.dispatch_group_wait
dispatch_group_wait會同步地等待group中所有的block執(zhí)行完畢后才繼續(xù)執(zhí)行,類似于dispatch barrier
應(yīng)用場景
場景1:
某個(gè)頁面加載時(shí)通過網(wǎng)絡(luò)請求獲得相應(yīng)的數(shù)據(jù),有的時(shí)候加載的內(nèi)容需要通過好幾個(gè)接口的數(shù)據(jù)組合而成,比如2個(gè)請求A和B,通常將B請求放在A請求成功回調(diào)中發(fā)起,在B的成功回調(diào)中組合起來。
會產(chǎn)生的問題:
1.請求多了,要寫多層的嵌套。
2.如果在除了最后一個(gè)請求前的某個(gè)請求失敗了,不會執(zhí)行后面的請求。
3.請求變成同步的,網(wǎng)絡(luò)差的情況下,如果有n個(gè)請求,以為著用戶要等待n倍于并發(fā)請求的時(shí)間才能看到內(nèi)容。
假設(shè)要上傳4張圖片
NSMutableArray *imageURLs= [NSMutableArray array];
//1.創(chuàng)建dispatch_group任務(wù)組
dispatch_group_t group =dispatch_group_create();
for (UIImage *image in images) {
//2.往group里面增加一個(gè)block任務(wù),這邊的block任務(wù)就是上傳一張圖片
dispatch_group_enter(group);
sendPhoto(image, success:^(NSString *url) {
[imageURLs addObject:url];
//3.表示任務(wù)已經(jīng)完成 需要移除
dispatch_group_leave(group);
});
}
//4.當(dāng)group中的block任務(wù)都執(zhí)行完畢以后,dispatch_group_notify 會被執(zhí)行
dispatch_group_notify(group, dispatch_get_global_queue(), ^{
postFeed(imageURLs, text);
});
GCD定時(shí)器
NStimer是對GCD定時(shí)器的包裝。GCD定時(shí)器更加的高級,且不受runloop的影響。
@interface ViewController ()
@property (nonatomic, strong) dispatch_source_t timer;
@end
int count = 0;
- (void)GCDTimer{
1.獲得隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
2.創(chuàng)建一個(gè)定時(shí)器(dispatch_source_t本質(zhì)是一個(gè)OC對象)
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
3.設(shè)置定時(shí)器的各種屬性(幾時(shí)開始任務(wù),每個(gè)多長時(shí)間執(zhí)行一次)
GCD的時(shí)間參數(shù),一般是納秒(1秒 == 10的9次方納秒)
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, 3.0 * NSEC_PER_SEC);//何時(shí)開始第一個(gè)任務(wù)
dispatch_time_t interval = 2.0 * NSEC_PER_SEC; //何時(shí)開始重復(fù)任務(wù)
dispatch_source_set_timer(self.timer, start, interval, 0);
4.設(shè)置回調(diào)
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"-------%@",[NSThread currentThread]);
count ++;
if(count == 5)
{
//取消定時(shí)器
dispatch_cancel(self.timer);
self.timer = nil;
}
});
5.啟動timer
dispatch_resume(self.timer);
}