GCD (Grand Central Dispatch)
概念
關(guān)注兩個(gè)概念:隊(duì)列硅确、任務(wù)。
iOS 多線(xiàn)程方案:pthread缭付、NSThread陷猫、NSOperation、GCD
- 隊(duì)列(Queue)和任務(wù)
GCD提供了dispatch queues來(lái)處理代碼塊足陨,這些隊(duì)列管理所提供給GCD的任務(wù)并用FIFO順序執(zhí)行這些任務(wù)娇未。這樣才能保證第一個(gè)被添加到隊(duì)列里的任務(wù)會(huì)是隊(duì)列中第一個(gè)開(kāi)始的任務(wù),而第二個(gè)被添加的任務(wù)將第二個(gè)開(kāi)始镊讼,如此直到隊(duì)列的終點(diǎn)蝶棋。
調(diào)度隊(duì)列(dispath queue)是一個(gè)對(duì)象,它以 FIFO 的方式管理提交的任務(wù)兼贸。GCD有三種隊(duì)列類(lèi)型:
- 串行隊(duì)列吃溅、
- 并行隊(duì)列、
- 主隊(duì)列
GCD中的任務(wù)只是一個(gè)代碼塊很澄,它可以指一個(gè)block或者函數(shù)指針甩苛。根據(jù)這個(gè)代碼塊添加進(jìn)入隊(duì)列的方式俏站,將任務(wù)分為同步任務(wù)和異步任務(wù):
同步任務(wù),使用dispatch_sync將任務(wù)加入隊(duì)列墨林;
異步任務(wù)犯祠,使用dispatch_async將任務(wù)加入隊(duì)列衡载。
串行(Serial)、并發(fā)(Concurrent)
串行(Serial)弃榨,指同一時(shí)間每次只能執(zhí)行一個(gè)任務(wù)梨睁。
并發(fā)(Concurrent),指同一時(shí)間可以同時(shí)執(zhí)行多個(gè)任務(wù)官辈。并發(fā)在異步(dispatch_async)函數(shù)下才有效钧萍。
同步、異步队魏、并行 万搔、串行
- 同步和異步?jīng)Q定了要不要開(kāi)啟新的線(xiàn)程
同步:在當(dāng)前線(xiàn)程中執(zhí)行任務(wù)瞬雹,不具備開(kāi)啟新線(xiàn)程的能力
異步:在新的線(xiàn)程中執(zhí)行任務(wù),具備開(kāi)啟新線(xiàn)程的能力 - 并發(fā)和串行決定了任務(wù)的執(zhí)行方式
并發(fā):多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行
串行:一個(gè)任務(wù)執(zhí)行完畢后呢诬,再執(zhí)行下一個(gè)任務(wù)
代碼段
- dispatch_async
這種用法非常常見(jiàn)胖缤,比如開(kāi)啟一個(gè)異步的網(wǎng)絡(luò)請(qǐng)求,待數(shù)據(jù)返回后返回主隊(duì)列刷新UI哪廓;又比如請(qǐng)求圖片,待圖片返回刷新UI等
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalQueue, ^{
// 一個(gè)異步的任務(wù)分俯,例如網(wǎng)絡(luò)請(qǐng)求缸剪,耗時(shí)的文件操作
// do something
dispatch_async(dispatch_get_main_queue(), ^{
// UI刷新
// do something
});
});
- dispatch_after
// 在 1.6 秒后剧劝,將任務(wù)加入隊(duì)列
NSTimeInterval delayTime = 1.6f;
dispatch_time_t delayTime_t = dispatch_time(DISPATCH_TIME_NOW,(int64_t)(delayTime * NSEC_PER_SEC));
dispatch_after(delayTime_t,dispatch_get_main_queue(), ^(void){
// do something
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(delayTime * NSEC_PER_SEC)),dispatch_get_main_queue(), ^(void){
// do something
});
// 另一種常用實(shí)現(xiàn)
[self preformSelector:@selector(todoMethod:) withObject:nil afterDelay:5.f];
- dispatch_once
// 單例
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
// do something
});
- dispatch_group
dispatch_group_create 創(chuàng)建一個(gè)調(diào)度組讥此,通過(guò) dispatch_group_async 將任務(wù)分別添加到該組中萄喳,在組中的所有任務(wù)執(zhí)行完成后回調(diào)(dispatch_group_notify)蹋半。
UIImageView *imageView1 = [[UIImageView alloc]init];
UIImageView *imageView2 = [[UIImageView alloc]init];
// 下載多張圖片并且要求圖片都下載完成才更新 UI
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 異步下載圖片
dispatch_async(globalQueue, ^{
dispatch_group_t group = dispatch_group_create();
__block UIImage *image1 = nil;
__block UIImage *image2 = nil;
// 添加任務(wù)到 group
dispatch_group_async(group, globalQueue, ^{
NSURL *url = [NSURL URLWithString:@"pic URL"];
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
});
dispatch_group_async(group, globalQueue, ^{
NSURL *url = [NSURL URLWithString:@"pic URL"];
image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
});
// group 執(zhí)行完回調(diào),在主線(xiàn)程更新 UI
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
imageView1.image = image1;
imageView2.image = image2;
});
});
- dispatch_apply
size_t times = 10;
dispatch_apply(times, dispatch_get_global_queue(0, 0), ^(size_t index){
// 執(zhí)行10次代碼染突,index順序不確定
});
- dispatch_barrier_async
在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行捻爷,而且它后面的任務(wù)等它執(zhí)行完成之后才會(huì)執(zhí)行;不能是全局的并發(fā)隊(duì)列份企;所有的任務(wù)都必須在一個(gè)隊(duì)列中也榄。
// dispatch_barrier_async的作用是承上啟下,保證此前的任務(wù)都先于自己執(zhí)行司志,此后的任務(wù)也遲于自己執(zhí)行甜紫。
// 本例中,任務(wù)4會(huì)在任務(wù)1骂远、2囚霸、3都執(zhí)行完之后執(zhí)行,而任務(wù)5激才、6會(huì)等待任務(wù)4執(zhí)行完后執(zhí)行。
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
// 任務(wù)1
...
});
dispatch_async(queue, ^{
// 任務(wù)2
...
});
dispatch_async(queue, ^{
// 任務(wù)3
...
});
dispatch_barrier_async(queue, ^{
// 任務(wù)4
...
});
dispatch_async(queue, ^{
// 任務(wù)5
...
});
dispatch_async(queue, ^{
// 任務(wù)6
...
});
- UI 更新只能在主線(xiàn)程中進(jìn)行
// 主線(xiàn)程刷新 tableView
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reload];
});
// 常用異步下載圖片
UIImageView *imageView = [[UIImageView alloc]init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:@"pic URL"];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
// 回到主線(xiàn)程更新 UI
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = image;
});
});
參考:
GCD日記
巧談GCD
iOS筆記-多線(xiàn)程相關(guān)(pthread 瘸恼、NSThread 劣挫、GCD、NSOperation)
由淺入深學(xué)習(xí)GCD??
GCD 深入理解(二)