GCD

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)后出
  • 執(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í)行
  • 容易混淆的術(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ù)

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ì)列中
    • 會(huì)開(kāi)多條線程嗤锉,所有的任務(wù)是并發(fā)執(zhí)行的
    • 注意:使用GCD的時(shí)候渔欢,具體開(kāi)幾條線程,并不是由任務(wù)的數(shù)量來(lái)決定的瘟忱,是由系統(tǒng)自動(dòng)決定
      • 會(huì)看CPU的處理情況奥额,線程是可以復(fù)用的
  • 異步函數(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ì)列中
    • 會(huì)開(kāi)啟一條子線程,所有的任務(wù)都是串行執(zhí)行的触菜,需要等前一個(gè)任務(wù)執(zhí)行完九榔,后面的任務(wù)才會(huì)執(zhí)行
  • 同步函數(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ì)列中
    • 不會(huì)開(kāi)啟新的線程,所有的任務(wù)都在當(dāng)前線程中串行執(zhí)行
  • 同步函數(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ì)列中
    • 不會(huì)開(kāi)啟新的線程丙号,所有的任務(wù)都在當(dāng)前線程中串行執(zhí)行
  • 同步函數(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ù)量并不是由任務(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ì)列
  • 特點(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ì)列+同步函數(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ù)
  • 開(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;
            })
    • 配置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í)行了
快速迭代
  • 迭代 - 遞歸 - 遍歷 - 博客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ù)組(快速迭代)
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()和dispatch_async()的區(qū)別

    • 相同點(diǎn):
      • 封裝任務(wù)
      • 把任務(wù)添加到隊(duì)列
    • 不同點(diǎn)
      • 隊(duì)列組能夠監(jiān)聽(tīng)該任務(wù)的執(zhí)行情況(開(kāi)始|結(jié)束)
  • 隊(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;
          })
          })

補(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就可以了
  • 全局并發(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版本源碼
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市乳怎,隨后出現(xiàn)的幾起案子彩郊,更是在濱河造成了極大的恐慌,老刑警劉巖蚪缀,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焦辅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡椿胯,警方通過(guò)查閱死者的電腦和手機(jī)筷登,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)哩盲,“玉大人前方,你說(shuō)我怎么就攤上這事×停” “怎么了惠险?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)抒线。 經(jīng)常有香客問(wèn)我班巩,道長(zhǎng),這世上最難降的妖魔是什么嘶炭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任抱慌,我火速辦了婚禮逊桦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抑进。我一直安慰自己强经,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布寺渗。 她就那樣靜靜地躺著匿情,像睡著了一般。 火紅的嫁衣襯著肌膚如雪信殊。 梳的紋絲不亂的頭發(fā)上炬称,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音涡拘,去河邊找鬼转砖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鲸伴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播晋控,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼汞窗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赡译?” 一聲冷哼從身側(cè)響起仲吏,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝌焚,沒(méi)想到半個(gè)月后裹唆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡只洒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年许帐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毕谴。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡成畦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涝开,到底是詐尸還是另有隱情循帐,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布舀武,位于F島的核電站拄养,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏银舱。R本人自食惡果不足惜瘪匿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一跛梗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柿顶,春花似錦茄袖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至家乘,卻和暖如春蝗羊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仁锯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工耀找, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人业崖。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓野芒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親双炕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狞悲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容