GCD概念簡(jiǎn)單理解
GCD是基于C的Api弦聂。不需要自己管理線程生死鸟辅。只需要?jiǎng)?chuàng)建隊(duì)列,把任務(wù)放進(jìn)隊(duì)列里面就可以了莺葫》肆梗看上去很簡(jiǎn)單,其實(shí)也是有一段心酸路捺檬。
GCD有兩個(gè)核心概念再层。一個(gè)是任務(wù),一個(gè)是隊(duì)列。
同步函數(shù):在當(dāng)前線程中執(zhí)行聂受,不開啟新的線程
dispatch_sync(dispatch_queue_t queue, dispatch_block_tblock);
異步函數(shù):具備開啟線程的能力蒿秦。
dispatch_async(dispatch_queue_t queue, dispatch_block_tblock);
隊(duì)列
并發(fā)隊(duì)列
自動(dòng)開啟多個(gè)線程,并且可以讓多個(gè)任務(wù)同時(shí)執(zhí)行蛋济。
僅僅在異步函數(shù)(dispatch_async)下有效棍鳖。
串行隊(duì)列
讓線程一個(gè)接著一個(gè)的執(zhí)行。一條線程執(zhí)行完后再執(zhí)行下一條線程碗旅。
并發(fā)隊(duì)列
并發(fā)隊(duì)列不需要手動(dòng)創(chuàng)建渡处。以下是創(chuàng)建代碼。
dispatch_queue_tdispatch_get_global_queue(
dispatch_queue_priority_tpriority,// 隊(duì)列的優(yōu)先級(jí)
unsignedlongflags);// 此參數(shù)暫時(shí)無用扛芽,用0即可
dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//獲得全局并發(fā)隊(duì)列
全局并發(fā)隊(duì)列的優(yōu)先級(jí)
#defineDISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#defineDISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)
#defineDISPATCH_QUEUE_PRIORITY_LOW (-2)// 低
#defineDISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺(tái)
串行隊(duì)列
使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列
dispatch_queue_t
dispatch_queue_create(constchar*label, //隊(duì)列名稱
dispatch_queue_attr_tattr);//隊(duì)列屬性骂蓖,一般用NULL即可
dispatch_queue_tqueue = dispatch_queue_create("isQueue", NULL);//創(chuàng)建
dispatch_release(queue);//非ARC時(shí)候需要釋放手動(dòng)創(chuàng)建的隊(duì)列
使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列)
主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列
放在主隊(duì)列中的任務(wù),都會(huì)放到主線程中執(zhí)行
使用dispatch_get_main_queue()獲得主隊(duì)列
dispatch_queue_tqueue = dispatch_get_main_queue();
使用dispatch_sync同步函數(shù)時(shí)候川尖,在主線程中往主隊(duì)列添加任務(wù)會(huì)造成死鎖登下。
隊(duì)列與任務(wù)的結(jié)合
函數(shù) | 全局并發(fā)隊(duì)列 | 手動(dòng)創(chuàng)建串行隊(duì)列 | 主隊(duì)列 |
---|---|---|---|
同步 (sync) | 沒有開啟新線程 串行執(zhí)行任務(wù) | 沒有開啟新線程 串行執(zhí)行任務(wù) | 沒有開啟新線程 串行執(zhí)行任務(wù) |
異步 (async) | 有開啟新線程 并發(fā)執(zhí)行任務(wù) | 有開啟新線程 串行執(zhí)行任務(wù) | 沒有開啟新線程 串行執(zhí)行任務(wù) |
線程間的通訊
更新UI,數(shù)據(jù)等都是要回到主線程的。不能在子線程叮喳。
//獲取全局隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"-子線程-- 開始下載圖片--%@",[NSThread currentThread]);
//下載數(shù)據(jù)是耗時(shí)操作放到子線程
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/b219ebc4b74543a94369f4cb1c178a82b9011442.jpg"]]];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"-主線程-- 刷新UI--%@",[NSThread currentThread]);
//回到主線程刷新UI
self.imageView.image = image;
});
});
延時(shí)操作
延時(shí)操作不會(huì)堵塞當(dāng)前線程.
//延遲操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)),//從什么時(shí)候開始被芳,是一個(gè)固定的算法
dispatch_get_main_queue(),//隊(duì)列
^{
//做要做的操作
});
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#pragma mark 延遲操作創(chuàng)建一
//獲取全局隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//延時(shí)多久
dispatch_time_t whenTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
//延時(shí)操作,根據(jù)whenTime設(shè)計(jì)的時(shí)間
dispatch_after(whenTime, queue, ^{
NSLog(@"倒計(jì)時(shí)結(jié)束");
dispatch_async(queue, ^{
NSLog(@"-子線程-- 開始下載圖片--%@",[NSThread currentThread]);
//下載數(shù)據(jù)是耗時(shí)操作放到子線程
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/b219ebc4b74543a94369f4cb1c178a82b9011442.jpg"]]];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"-主線程-- 刷新UI--%@",[NSThread currentThread]);
//回到主線程刷新UI
self.imageView.image = image;
});
});
});
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#pragma mark 延遲操作創(chuàng)建二
//獲取全局隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"倒計(jì)時(shí)結(jié)束");
dispatch_async(queue, ^{
NSLog(@"-子線程-- 開始下載圖片--%@",[NSThread currentThread]);
//下載數(shù)據(jù)是耗時(shí)操作放到子線程
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/b219ebc4b74543a94369f4cb1c178a82b9011442.jpg"]]];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"-主線程-- 刷新UI--%@",[NSThread currentThread]);
//回到主線程刷新UI
self.imageView.image = image;
});
});
});
GCD一次性代碼
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//代碼只執(zhí)行一次
});
});
GCD隊(duì)列組
分組模式 dispatch_group_notify
可以異步執(zhí)行多個(gè)耗時(shí)操作馍悟。等耗時(shí)操作都執(zhí)行完畢之后會(huì)回到主線程執(zhí)行操作畔濒。主要用于監(jiān)聽任務(wù)是否完成。
//獲取全局隊(duì)列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//創(chuàng)建一個(gè)隊(duì)列組
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, globalQueue, ^{
NSLog(@"--- 1 開始--- %@",[NSThread currentThread]);
//延時(shí)5秒 模仿堵塞子線程
[NSThread sleepForTimeInterval:5];
NSLog(@"--- 2 --- 完成 %@",[NSThread currentThread]);
});
dispatch_group_async(group, globalQueue, ^{
NSLog(@"--- 2 開始--- %@",[NSThread currentThread]);
//延時(shí)5秒 模仿堵塞子線程
[NSThread sleepForTimeInterval:5];
NSLog(@"--- 2 --- 完成 %@",[NSThread currentThread]);
});
//在這個(gè)隊(duì)列組里面锣咒,會(huì)等group中的全部代碼執(zhí)行完畢再去執(zhí)行其它的操作
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的異步操作都執(zhí)行完畢后侵状,回到主線程...
NSLog(@"全部完成");
});
//非ARC時(shí)候要釋放掉
//dispatch_release(group);
dispatch_apply組內(nèi)無序循環(huán)執(zhí)行任務(wù)
//循環(huán)執(zhí)行任務(wù),并且執(zhí)行任務(wù)的順序是無序列的毅整。這里會(huì)堵塞當(dāng)前的線程趣兄。所以要注意。一般都是在子線程中執(zhí)行悼嫉。
dispatch_apply(size_t iterations,//執(zhí)行的次數(shù)
<#dispatch_queue_t queue#>,//隊(duì)列
<#^(size_t)block#>)//任務(wù)
dispatch_apply(5, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
NSLog(@"%zu",index);
});
dispatch_set_target_queue 變更queue的優(yōu)先級(jí)別
dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.queue", NULL);
//設(shè)置這個(gè)全局并發(fā)隊(duì)列的優(yōu)先級(jí)為后臺(tái)
dispatch_queue_t globalQueued = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(exampleQueue, globalQueued);
/**
* 經(jīng)過轉(zhuǎn)換之后exampleQueue的優(yōu)先級(jí)別變成后臺(tái)
*/