GCD
GCD簡(jiǎn)介
- Grand Central Dispatch中樞調(diào)度器
- 純C語(yǔ)言的,提供了非常強(qiáng)大的函數(shù)
- 優(yōu)勢(shì)
- GCD是蘋(píng)果公司為多核的并行運(yùn)算提出的解決方案
- GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核轻掩、四核)拙友,充分利用設(shè)備的多核
- GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程垂寥、調(diào)度任務(wù)、銷(xiāo)毀線程)
- github上面有源碼
任務(wù)和隊(duì)列
- GCD中的核心概念
- 任務(wù):執(zhí)行什么操作柑晒,需要用函數(shù)封裝起來(lái)(同步函數(shù)|異步函數(shù))
- 隊(duì)列:用來(lái)存放任務(wù)的
- 使用步驟
- 定制任務(wù)
- 確定想要做的事情
- 將任務(wù)添加到隊(duì)列中
- GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出缴守,放到對(duì)應(yīng)的線程中執(zhí)行
- 任務(wù)的取出遵循隊(duì)列的FIFO原則:先進(jìn)先出细燎,后進(jìn)后出
- 定制任務(wù)
- 執(zhí)行任務(wù)
- 同步
- dispatch_sync(dispatch_queue_t queue,dispatch_block_t block)
- 只能在當(dāng)前線程中執(zhí)行任務(wù)两曼,不具備開(kāi)啟新線程的能力
- 異步
- dispatch_asyn
- 可以在新的線程中執(zhí)行任務(wù),具備開(kāi)啟新線程的能力
- 同步
- 隊(duì)列的類(lèi)型
- 并發(fā)隊(duì)列
- 可以讓多個(gè)任務(wù)并發(fā)執(zhí)行
- 并發(fā)功能只有在異步函數(shù)下才有效
- 串行隊(duì)列
- 讓任務(wù)一個(gè)接著一個(gè)的執(zhí)行
- 并發(fā)隊(duì)列
- 容易混淆的術(shù)語(yǔ)
- 同步異步:能不能開(kāi)啟新的線程
- 同步:只是在當(dāng)前線程中執(zhí)行任務(wù)玻驻,不具備開(kāi)啟新線程的能力
- 異步:可以在新的線程中執(zhí)行任務(wù)悼凑,具備開(kāi)啟新線程的能力
- 并發(fā)|串行:任務(wù)的執(zhí)行方式
- 并發(fā):允許多個(gè)任務(wù)并發(fā)執(zhí)行
- 串行:一個(gè)任務(wù)執(zhí)行完畢之后,再執(zhí)行下一個(gè)任務(wù)
- 同步異步:能不能開(kāi)啟新的線程
GCD基本使用
四種組合方式
-
異步函數(shù)+并發(fā)隊(duì)列
- 獲得隊(duì)列
- dispatch_queue_t 結(jié)構(gòu)體
- dispatch_queue_create("com.520it,www.download",DISPATCH_QUEUE_CONCURRENT)創(chuàng)建
- 第一個(gè)參數(shù):C語(yǔ)言的字符串璧瞬,給隊(duì)列起一個(gè)名字(推薦寫(xiě)法:公司域名倒過(guò)來(lái)寫(xiě)户辫,后面跟上作用)名字的作用:是用來(lái)調(diào)試的
- 第二個(gè)參數(shù):隊(duì)列的類(lèi)型,傳一個(gè)宏
- DISPATCH_QUEUE_CONCURRENT
- DISPATCH_QUEUE_SERIAL
- 封裝任務(wù)并且把任務(wù)添加到隊(duì)列中
- dispatch_async(queue,任務(wù))
- 第一個(gè)參數(shù):隊(duì)列
- 第二個(gè)參數(shù):block可以封裝一個(gè)任務(wù)
- 封裝任務(wù)
- 把任務(wù)添加到隊(duì)列中
- dispatch_async(queue,任務(wù))
- 會(huì)開(kāi)多條線程嗤锉,所有的任務(wù)是并發(fā)執(zhí)行的
- 注意:使用GCD的時(shí)候渔欢,具體開(kāi)幾條線程,并不是由任務(wù)的數(shù)量來(lái)決定的瘟忱,是由系統(tǒng)自動(dòng)決定
- 會(huì)看CPU的處理情況奥额,線程是可以復(fù)用的
- 獲得隊(duì)列
-
異步函數(shù)+串行隊(duì)列
- 獲得隊(duì)列
- dispatch_queue_t 結(jié)構(gòu)體
- dispatch_queue_create("com.520it,www.download",DISPATCH_QUEUE_SERIAL)創(chuàng)建
- 第一個(gè)參數(shù):C語(yǔ)言的字符串,給隊(duì)列起一個(gè)名字(推薦寫(xiě)法:公司域名倒過(guò)來(lái)寫(xiě)访诱,后面跟上作用)
- 第二個(gè)參數(shù):隊(duì)列的類(lèi)型垫挨,傳一個(gè)宏
- DISPATCH_QUEUE_CONCURRENT
- DISPATCH_QUEUE_SERIAL
- 封裝任務(wù)并且把任務(wù)添加到隊(duì)列中
- dispatch_async(queue,任務(wù))
- 第一個(gè)參數(shù):隊(duì)列
- 第二個(gè)參數(shù):block可以封裝一個(gè)任務(wù)
- 封裝任務(wù)
- 把任務(wù)添加到隊(duì)列中
- dispatch_async(queue,任務(wù))
- 會(huì)開(kāi)啟一條子線程,所有的任務(wù)都是串行執(zhí)行的触菜,需要等前一個(gè)任務(wù)執(zhí)行完九榔,后面的任務(wù)才會(huì)執(zhí)行
- 獲得隊(duì)列
-
同步函數(shù)+并行隊(duì)列
- 獲得隊(duì)列
- dispatch_queue_t 結(jié)構(gòu)體
- dispatch_queue_create("com.520it,www.download",DISPATCH_QUEUE_CONCURRENT)創(chuàng)建
- 第一個(gè)參數(shù):C語(yǔ)言的字符串,給隊(duì)列起一個(gè)名字(推薦寫(xiě)法:公司域名倒過(guò)來(lái)寫(xiě)涡相,后面跟上作用)
- 第二個(gè)參數(shù):隊(duì)列的類(lèi)型哲泊,傳一個(gè)宏
- DISPATCH_QUEUE_CONCURRENT
- DISPATCH_QUEUE_SERIAL
- 封裝任務(wù)并且把任務(wù)添加到隊(duì)列中
- dispatch_sync(queue,任務(wù))
- 第一個(gè)參數(shù):隊(duì)列
- 第二個(gè)參數(shù):block可以封裝一個(gè)任務(wù)
- 封裝任務(wù)
- 把任務(wù)添加到隊(duì)列中
- dispatch_sync(queue,任務(wù))
- 不會(huì)開(kāi)啟新的線程,所有的任務(wù)都在當(dāng)前線程中串行執(zhí)行
- 獲得隊(duì)列
-
同步函數(shù)+串行隊(duì)列
- 獲得隊(duì)列
- dispatch_queue_t 結(jié)構(gòu)體
- dispatch_queue_create("com.520it,www.download",DISPATCH_QUEUE_SERIALRENT)創(chuàng)建
- 第一個(gè)參數(shù):C語(yǔ)言的字符串催蝗,給隊(duì)列起一個(gè)名字(推薦寫(xiě)法:公司域名倒過(guò)來(lái)寫(xiě)切威,后面跟上作用)
- 第二個(gè)參數(shù):隊(duì)列的類(lèi)型,傳一個(gè)宏
- DISPATCH_QUEUE_CONCURRENT
- DISPATCH_QUEUE_SERIAL
- 封裝任務(wù)并且把任務(wù)添加到隊(duì)列中
- dispatch_sync(queue,任務(wù))
- 第一個(gè)參數(shù):隊(duì)列
- 第二個(gè)參數(shù):block可以封裝一個(gè)任務(wù)
- 封裝任務(wù)
- 把任務(wù)添加到隊(duì)列中
- dispatch_sync(queue,任務(wù))
- 不會(huì)開(kāi)啟新的線程丙号,所有的任務(wù)都在當(dāng)前線程中串行執(zhí)行
- 獲得隊(duì)列
同步函數(shù)不管是串行還是并發(fā)都是串行執(zhí)行任務(wù)的先朦。
全局并發(fā)隊(duì)列
-
并發(fā)隊(duì)列
- 隊(duì)列中的任務(wù)可以同時(shí)執(zhí)行
- 并發(fā)隊(duì)列分為兩種
- 自己創(chuàng)建的并發(fā)隊(duì)列dispatch_queue_create
- 全局并發(fā)隊(duì)列(默認(rèn)存在)
GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列且预,供整個(gè)應(yīng)用使用,可以無(wú)需手動(dòng)創(chuàng)建
-
dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊(duì)列
- 參數(shù)一:隊(duì)列的優(yōu)先級(jí)dispatch_queue_priority
- DISPATCH_QUEUE_PRIORITY_DEFAULT 默認(rèn)優(yōu)先級(jí) == 0 烙无,不要傳其他的,會(huì)引發(fā)線程安全問(wèn)題(反轉(zhuǎn))
- 參數(shù)二:暫時(shí)無(wú)用遍尺,用0即可截酷,給未來(lái)使用的
- 參數(shù)一:隊(duì)列的優(yōu)先級(jí)dispatch_queue_priority
注意:線程的數(shù)量并不是由任務(wù)的數(shù)量決定的(是由系統(tǒng)決定的)
主隊(duì)列
- 串行隊(duì)列
- 必須一個(gè)接著一個(gè)的執(zhí)行,要等當(dāng)前任務(wù)執(zhí)行完畢之后乾戏,才能執(zhí)行后面的任務(wù)
- 串行隊(duì)列有兩種
- 自己創(chuàng)建的串行隊(duì)列dispatch_queue_create("com.520it,www.download",DISPATCH_QUEUE_SERIAL)
- DISPATCH_QUEUE_SERIAL == NULL
- 主隊(duì)列(和主線程相關(guān))
- 主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列
- 放在主隊(duì)列中的任務(wù)迂苛,都會(huì)放到主線程中執(zhí)行 | 調(diào)度的時(shí)候比較特殊!
- dispatch_get_main_queue()獲得主隊(duì)列
- 自己創(chuàng)建的串行隊(duì)列dispatch_queue_create("com.520it,www.download",DISPATCH_QUEUE_SERIAL)
- 特點(diǎn):
- 凡是放在主隊(duì)列中的任務(wù)都必須要在主線程中執(zhí)行
- 本身是一個(gè)串行隊(duì)列,串行隊(duì)列的特點(diǎn)它都有
- 如果主隊(duì)列中有任務(wù)需要執(zhí)行鼓择,那么主隊(duì)列會(huì)安排主線程來(lái)執(zhí)行當(dāng)前隊(duì)列中的任務(wù)三幻,但是在調(diào)度之前,會(huì)先檢查主線程的狀態(tài)呐能,如果主線程空閑念搬,如果主線程在忙,就暫停調(diào)度隊(duì)列中的任務(wù)摆出,等到主線程空閑的時(shí)候再調(diào)度朗徊。
- 主隊(duì)列+異步函數(shù)
- 獲得主隊(duì)列
- dispatch_get_main_queue()
- 添加任務(wù)到隊(duì)列中
- dispatch_async()
- 不會(huì)開(kāi)線程,所有的任務(wù)都在
主線程
中串行執(zhí)行
- 獲得主隊(duì)列
- 主隊(duì)列+同步函數(shù)
- 獲得主隊(duì)列
- dispatch_get_main_queue()
- 添加任務(wù)到隊(duì)列中
- dispatch_sync()
- 任務(wù)并沒(méi)有執(zhí)行偎漫,有一個(gè)死鎖
- 主隊(duì)列里的任務(wù)必須要在主線程中執(zhí)行
- 主線程在執(zhí)行同步函數(shù)
- 主隊(duì)列工作模式:如果發(fā)現(xiàn)隊(duì)列中有任務(wù)爷恳,那么就安排主線程來(lái)執(zhí)行,但是在安排之前象踊, 會(huì)先檢查主線程的狀態(tài)(看主線程是否空閑)温亲,如果主線程在忙,那么就暫停調(diào)度杯矩,直到主線程空閑
- 如果在子線程中調(diào)度就不會(huì)死鎖
- performSelectorInBackground:@selector(主隊(duì)列+同步函數(shù)) withObject:
- 不會(huì)發(fā)生死鎖了栈虚,為什么?
- 主線程空閑菊碟,沒(méi)有事情做节芥,主線程就執(zhí)行了任務(wù)
- 獲得主隊(duì)列
開(kāi)發(fā)中,常用的是:異步函數(shù)+并發(fā)隊(duì)列|串行隊(duì)列逆害,面試中會(huì)把代碼給你头镊,問(wèn)你打印的結(jié)果是什么
-
問(wèn)題:同步函數(shù)+主隊(duì)列會(huì)死鎖?異步函數(shù)+主隊(duì)列不會(huì)死鎖魄幕?
- 同步異步:
- 是否具有開(kāi)線程的能力
- 同步函數(shù)同步執(zhí)行任務(wù)相艇,異步函數(shù)異步執(zhí)行任務(wù)
- 同步執(zhí)行:
- 必須要等當(dāng)前任務(wù)執(zhí)行完,才能執(zhí)行后面的任務(wù)纯陨,如果我沒(méi)有執(zhí)行坛芽,那么我后面的也別想執(zhí)行
- 異步執(zhí)行:
- 我開(kāi)始執(zhí)行后留储,可以不用等我執(zhí)行完,就執(zhí)行后面的任務(wù)
- 異步函數(shù)+主隊(duì)列不會(huì)發(fā)生死鎖
- 獲得一個(gè)主隊(duì)列
- 同步函數(shù)
- 封裝一個(gè)任務(wù)
- 把任務(wù)添加到隊(duì)列中去咙轩,檢查主線程狀態(tài)(較忙)死鎖
- 異步函數(shù)
- 隊(duì)列中有任務(wù)获讳,要求主線程去執(zhí)行
- 異步函數(shù)異步執(zhí)行,跳過(guò)任務(wù)活喊,把任務(wù)存在隊(duì)列中
- 代碼執(zhí)行完畢后,主線程空閑了丐膝,就回來(lái)再執(zhí)行隊(duì)列里的任務(wù),就不會(huì)發(fā)生死鎖
- 同步異步:
- 異步函數(shù) +并發(fā)隊(duì)列 ps 同步函數(shù)+并發(fā)隊(duì)列
- 1.start - end - 任務(wù) - 異步
- 2.start - 任務(wù) - end - 同步
-
問(wèn)題:同步函數(shù)+串行隊(duì)列不會(huì)發(fā)生死鎖钾菊?
- 串行隊(duì)列帅矗,在當(dāng)前線程中執(zhí)行,串行隊(duì)列有任務(wù)就會(huì)執(zhí)行煞烫,不會(huì)檢查主線程的狀態(tài)浑此, 不管線程是否在忙,都會(huì)強(qiáng)行讓線程來(lái)執(zhí)行任務(wù)
-
總結(jié)
- 異步函數(shù)+不是主隊(duì)列就一定會(huì)開(kāi)線程
- 同步+并發(fā):不會(huì)線程滞详,串行執(zhí)行任務(wù)
- 同步+串行:不會(huì)開(kāi)線程凛俱,串行執(zhí)行任務(wù)
- 同步+主隊(duì)列:不會(huì)開(kāi)線程,死鎖
- 異步+并發(fā):開(kāi)多條線程茵宪,并發(fā)執(zhí)行任務(wù)
- 異步+串行:開(kāi)線程最冰,串行執(zhí)行任務(wù)
- 異步+主隊(duì)列:沒(méi)有開(kāi)啟新線程,串行執(zhí)行任務(wù)
線程間通信
- 開(kāi)子線程下載圖片
- 異步+非主隊(duì)列
- 獲得全局并發(fā)隊(duì)列
- dispatch_get_global_queue(0,0)
- 使用異步函數(shù)+并發(fā)隊(duì)列
- dispatch_async(queue,block)
- 確定URL
- 把圖片的二進(jìn)制數(shù)據(jù)下載到本地
- dataWithContentsOfURL:
- 轉(zhuǎn)化格式
- imageWithData:
- 顯示圖片
- 回到主線程刷新UI
- GCD可以嵌套
- dispatch_async(dispatch_get_main_queue(),^{
self.imageV.image = image;
})
- dispatch_async(queue,block)
- 配置info.plist文件
- 問(wèn):回到主線程稀火,是異步函數(shù)+主隊(duì)列暖哨,在這里可以用同步函數(shù)+主隊(duì)列嗎?
- 可以凰狞,當(dāng)前執(zhí)行的是子線程篇裁,不會(huì)發(fā)生死鎖
常用函數(shù)
- 開(kāi)發(fā)中比較常用的GCD函數(shù)
延遲執(zhí)行
- 一段時(shí)間之后再執(zhí)行任務(wù)
- 三種方法可以實(shí)現(xiàn)延遲執(zhí)行
- 方法一:performSelector:withObject:afterDelay:
- 方法二:定時(shí)器NSTimer scheduledTimeWithTimeInterval:target:selector:userInfo:repeats:
- 方法三:GCD dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(3.0*NSEC_PER_SEC)),dispatch_get_main_queue),^{}
- 默認(rèn)是主隊(duì)列 ,可以改為全局并發(fā)隊(duì)列
- 隊(duì)列決定代碼塊在哪個(gè)線程中調(diào)用
- 主隊(duì)列 - 主線程
- 并發(fā)隊(duì)列 - 子線程
- 好處:可以控制在哪個(gè)線程里面執(zhí)行任務(wù)
- 延遲執(zhí)行內(nèi)部實(shí)現(xiàn)原理赡若?
- A:先把任務(wù)提交到隊(duì)列达布,然后三秒之后再執(zhí)行該任務(wù)(錯(cuò)誤)
- B:先等三秒的時(shí)間,然后再把任務(wù)提交到隊(duì)列
- 正確答案:B
- 延遲執(zhí)行就是延遲提交
一次性代碼
- 只會(huì)執(zhí)行一次,一輩子只會(huì)執(zhí)行一次
- dispatch_once(&onceToken,^{});
- 特點(diǎn):
- 整個(gè)程序運(yùn)行過(guò)程中逾冬,只會(huì)執(zhí)行一次
- 它本身是線程安全的黍聂,不用考慮線程安全的問(wèn)題
- 怎么做到永遠(yuǎn)只會(huì)執(zhí)行一次呢?
- 通過(guò)靜態(tài)變量的值來(lái)判斷的
- static dispatch_once_t onceToken;
- 判斷onceToken值是否等于0身腻,不等于零就不執(zhí)行了
- 通過(guò)靜態(tài)變量的值來(lái)判斷的
快速迭代
迭代 - 遞歸 - 遍歷 - 博客ios開(kāi)發(fā)中實(shí)用技巧
-
遍歷
- for循環(huán)产还,開(kāi)多條線程就可以提高效率
- GCD的快速迭代dispatch_apply(10,并發(fā)隊(duì)列嘀趟,^(size_t index){})
- 參數(shù)一:遍歷多少次脐区,size_t 類(lèi)似NSInteger類(lèi)型
- 參數(shù)二:對(duì)列,看到隊(duì)列就要想她按,block塊在哪個(gè)線程中調(diào)用
- 參數(shù)三:^(size_t ){}類(lèi)似于for循環(huán)里面的i
-
for循環(huán)與GCD的快速迭代區(qū)別
- 快速迭代沒(méi)有順序牛隅,開(kāi)始迭代的時(shí)候是按照順序開(kāi)始的炕柔,誰(shuí)先結(jié)束是不知道的,所以打印出的結(jié)果是沒(méi)有順序的媒佣,是并發(fā)執(zhí)行的
- GCD快速迭代:會(huì)開(kāi)啟多條子線程和主線程一起并發(fā)的執(zhí)行任務(wù)
- 注意:隊(duì)列怎么傳匕累?不能傳主隊(duì)列!不傳串行隊(duì)列默伍,不會(huì)死鎖哩罪,不會(huì)開(kāi)線程,執(zhí)行方式和for循環(huán)一樣巡验,串行執(zhí)行的!傳并發(fā)隊(duì)列5舛O陨琛!
- 用快速迭代就用并發(fā)隊(duì)列P帘妗2段妗!斗搞!
-
快速迭代的應(yīng)用
- 剪切文件
- 獲得路徑下面的子路徑(打印的是文件的名稱(chēng)指攒,剪切的時(shí)候需要的是文件的全路徑)
文件管理者NSFileManager defaultManager]subpathsAtPath: - 遍歷數(shù)組(快速迭代)
- 獲得路徑下面的子路徑(打印的是文件的名稱(chēng)指攒,剪切的時(shí)候需要的是文件的全路徑)
- 剪切文件
dispatch_get_global_queue(0,0)
dispatch_apply(subpaths.count,queue,^(size_t){
獲得文件的名稱(chēng)
獲得要剪切文件的全路徑(stringByAppendingPathComponent:該方法在拼接的時(shí)候會(huì)自動(dòng)添加一個(gè)/)
拼接文件的目標(biāo)路徑(toFullPath)
剪切文件
[NSFileManager defaultManager] moveItemAtpath:toPath:error:(第一個(gè)參數(shù):要剪切的文件在哪里?第二參數(shù):要剪切到哪里去僻焚,全路徑允悦;第三個(gè)參數(shù):)
})
柵欄函數(shù)
- 獲得隊(duì)列:并發(fā)
- dispatch_queue_create("",DISPATCH_QUEUE_CONCURRENT)
- 為什么不用全局并發(fā)隊(duì)列?
- 柵欄函數(shù)不能使用全局并發(fā)隊(duì)列
- 如果使用全局并發(fā)隊(duì)列虑啤,柵欄函數(shù)就不具備攔截功能隙弛,和普通的異步函數(shù)沒(méi)有任何區(qū)別
- 使用柵欄函數(shù),必須要自己創(chuàng)建隊(duì)列
- 異步函數(shù)
- dispatch_async(queue,^{})
- 需求:真實(shí)開(kāi)發(fā)中狞山,任務(wù)和任務(wù)之間有依賴(lài)關(guān)系全闷,有先后順序關(guān)系,要求執(zhí)行123三個(gè)任務(wù)后萍启,執(zhí)行打印操作总珠,再執(zhí)行后面的456三個(gè)任務(wù)
- 柵欄函數(shù)
- dispatch_barrier_async()一般用異步函數(shù)
- 在柵欄函數(shù)內(nèi)部執(zhí)行打印操作
- 作用:
- 等之前的所有任務(wù)都執(zhí)行完畢之后,執(zhí)行柵欄函數(shù)中的任務(wù)勘纯,等我的任務(wù)執(zhí)行完畢之后局服,在執(zhí)行后面的任務(wù)
- 前面的和后面的任務(wù)都是并發(fā)執(zhí)行的
GCD隊(duì)列組(掌握)
和柵欄函數(shù)的功能很類(lèi)似
-
1.獲得隊(duì)列
- 全局并發(fā)隊(duì)列dispatch_get_global_queue()
異步函數(shù)dispatch_async(queue,^{})
需求,在最后攔住任務(wù)屡律,當(dāng)所有的任務(wù)執(zhí)行完畢之后做一些事情腌逢!
隊(duì)列組(調(diào)度組)
-
2.創(chuàng)建隊(duì)列組dispatch_group_create()
- 監(jiān)聽(tīng)隊(duì)列里面所有任務(wù)的執(zhí)行情況
-
3.異步函數(shù)dispatch_group_async()
- 第一個(gè)參數(shù):隊(duì)列組
- 第二個(gè)參數(shù):隊(duì)列
- 通過(guò)隊(duì)列組建立起隊(duì)列組和隊(duì)列以及任務(wù)之間的關(guān)系
4.攔截dispatch_group_notify(group,queue,^{打印操作})當(dāng)隊(duì)列組中所有的任務(wù)都執(zhí)行完畢之后,會(huì)調(diào)用該方法
-
隊(duì)列組是如何知道任務(wù)什么時(shí)候結(jié)束的呢超埋?
- 以前是把dispatch_group_async(group,queue,^{})拆分成三個(gè)方法
- 1.創(chuàng)建隊(duì)列組
- 2.獲得對(duì)列
- 3.該方法后面的異步任務(wù)會(huì)被隊(duì)列組監(jiān)聽(tīng)dispatch_group_enter(group)
- 4.使用異步函數(shù)封裝任務(wù)
- dispatch_async(queue,^{任務(wù)1搏讶,在里面監(jiān)聽(tīng),enter和leave配對(duì)使用dispatch_group_leave(group)})
- 5.攔截通知佳鳖,隊(duì)列決定block塊在哪個(gè)線程中執(zhí)行 dispatch_group_notify(group,queue,^{})
- 以前是把dispatch_group_async(group,queue,^{})拆分成三個(gè)方法
-
dispatch_group_async()和dispatch_async()的區(qū)別
- 相同點(diǎn):
- 封裝任務(wù)
- 把任務(wù)添加到隊(duì)列
- 不同點(diǎn)
- 隊(duì)列組能夠監(jiān)聽(tīng)該任務(wù)的執(zhí)行情況(開(kāi)始|結(jié)束)
- 相同點(diǎn):
-
隊(duì)列組的應(yīng)用
- 應(yīng)用場(chǎng)景:下載圖片1,圖片2媒惕,把兩張圖片合成為一張圖片
- 耗時(shí)操作系吩,耗時(shí)操作放到子線程中執(zhí)行
- 要開(kāi)2~3條子線程
- 獲得一個(gè)并發(fā)隊(duì)列dispatch_get_global_queue(0,0)
- 合成圖片操作,有一個(gè)隱藏的依賴(lài)關(guān)系
- 隊(duì)列組
- 柵欄函數(shù)
- 創(chuàng)建隊(duì)列組dispatch_group_creat()
- 異步函數(shù)dispatch_group_async(group,queue^{
URL:URLWithString
把圖片的二進(jìn)制數(shù)據(jù)下載到本地dataWithContentOfURL:
轉(zhuǎn)換格式imageWithData
定義圖片的屬性妒蔚,強(qiáng)引用轉(zhuǎn)換好的圖片
}) - 合成圖片
- dispatch_group_notify(group,queue,^{
開(kāi)啟圖形上下文UIGraphicsBeginImageContext()
畫(huà)圖1和2 drawInRect:
根據(jù)上下文得到圖片 UIGraphicsGetImageFromCurrentImageContext()
關(guān)閉上下文UIGraphicsEndImageContext()
顯示圖片(線程間通信)
dispatch_async(dispatch_get_main_queue(),^{
self.imageV.image = image;
})
})
- dispatch_group_notify(group,queue,^{
- 應(yīng)用場(chǎng)景:下載圖片1,圖片2媒惕,把兩張圖片合成為一張圖片
補(bǔ)充
-
GCD的其他用法
- 使用函數(shù)的方法封裝任務(wù)dispatch_async_f()
- 第一個(gè)參數(shù):隊(duì)列
- 第二個(gè)參數(shù):函數(shù)要接收的參數(shù)NULL
- 第三個(gè)參數(shù):dispatch_function_t
- void(*dispatch_function_t)(void *)
- (*dispatch_function_t) -- run把第一個(gè)小括號(hào)替換成函數(shù)名稱(chēng)
- 第三個(gè)參數(shù)直接傳run就可以了
- 使用函數(shù)的方法封裝任務(wù)dispatch_async_f()
-
全局并發(fā)隊(duì)列與自己創(chuàng)建的并發(fā)隊(duì)列的區(qū)別
- 全局并發(fā)隊(duì)列在整個(gè)應(yīng)用程序中本身是默認(rèn)存在的穿挨,并且對(duì)應(yīng)有高優(yōu)先級(jí)、默認(rèn)優(yōu)先級(jí)肴盏、低優(yōu)先級(jí)和后臺(tái)優(yōu)先級(jí)一共四個(gè)并發(fā)隊(duì)列科盛,我們只選擇其中的一個(gè)直接拿來(lái)用,而creat函數(shù)是實(shí)打?qū)嵉膹念^開(kāi)始去創(chuàng)建一個(gè)隊(duì)列
- 在ios6.0之前菜皂,在GCD中凡是使用了create和retain的函數(shù)在最后都需要做一次release操作贞绵。而主隊(duì)列和全局并發(fā)隊(duì)列不需要我們手動(dòng)release.當(dāng)然了,在ios6.0之后GCD已經(jīng)被納入到了ARC的內(nèi)存管理范疇中恍飘,即便是使用retain或者create函數(shù)創(chuàng)建的對(duì)象也不再需要開(kāi)發(fā)人員手動(dòng)釋放榨崩,我們像對(duì)待普通OC對(duì)象一樣對(duì)待GCD就OK
- 在使用柵欄函數(shù)的時(shí)候,蘋(píng)果官方明確規(guī)定章母,柵欄函數(shù)只有在和使用create函數(shù)自己創(chuàng)建的并發(fā)隊(duì)列一起使用的時(shí)候才有效果(沒(méi)有給出具體原因)
- 其他區(qū)別涉及到XNU內(nèi)核的系統(tǒng)級(jí)線程編程母蛛,不一一列舉
- 參考
- GCDAPI
- Libdispatch版本源碼