GCD學(xué)習(xí)

GCD(Grand Central Dispatch)

核心是dispatch queue,隊(duì)列就是一系列的代碼塊(WorkItem任務(wù)項(xiàng)).一般耗時(shí)和需要CPU大量計(jì)算的時(shí)候要分在后臺(tái)線程,更新UI操作要放在主線程.

  • 創(chuàng)建dispatch queue

    let queue = DispatchQueue(label: "com.eric.myqueue")
    

    最好為隊(duì)列創(chuàng)建label.反向DNScom.eric.myqueue

  • 使用sync同步,async異步執(zhí)行

    //同步執(zhí)行
    queue.sync {
      for i in 0..<10 {
        print("??", i)
      }
    }
    //異步執(zhí)行
    queue.async {
      for i in 0..<10 {
        print("??", i)
      }
    }
    

Quality Of Service(QoS) 和優(yōu)先級(jí)

由于主隊(duì)列總是用來(lái)處理 UI 以及界面的響應(yīng),所以在主線程執(zhí)行的任務(wù)永遠(yuǎn)都有最高的優(yōu)先級(jí)

用于指定任務(wù)重要程度以及優(yōu)先級(jí)的信息,在 GCD 中被稱為 Quality of Service(QoS)

優(yōu)先級(jí)從大到小

  1. userInteractive
  2. userInitiated
  3. default
  4. utility
  5. background
  6. unspecified

主隊(duì)列執(zhí)行的任務(wù)有最高優(yōu)先級(jí)

優(yōu)先級(jí)隊(duì)列初始化方法:

let queue = DispatchQueue(label: "com.appcoda.queue1", qos: DispatchQoS.userInitiated)

并行隊(duì)列

使用attributes屬性設(shè)置concurrent并發(fā)隊(duì)列

let anotherQueue = DispatchQueue(label: "com.appcoda.anotherQueue", qos: .utility, attributes: .concurrent)
inactiveQueue = anotherQueue

這個(gè) attributes 參數(shù)也可以接受另一個(gè)名為 initiallyInactive 的值。如果使用這個(gè)值,任務(wù)不會(huì)被自動(dòng)執(zhí)行,而是需要開(kāi)發(fā)者手動(dòng)去觸發(fā)。

DispatchQueue 類的 activate() 方法會(huì)讓任務(wù)開(kāi)始執(zhí)行。注意,這個(gè)隊(duì)列并沒(méi)有被指定為并行隊(duì)列,因此它們會(huì)以串行的方式執(zhí)行

//手動(dòng)觸發(fā)
if let queue = inactiveQueue {
    queue.activate()
}

現(xiàn)在的問(wèn)題是,我們?nèi)绾卧谥付?initiallyInactive 的同時(shí)將隊(duì)列指定為并行隊(duì)列?其實(shí)很簡(jiǎn)單,我們可以將兩個(gè)值放入一個(gè)數(shù)組當(dāng)中,作為 attributes 的參數(shù),替代原本指定的單一數(shù)值:

let anotherQueue = DispatchQueue(label: "com.appcoda.anotherQueue", qos: .userInitiated, attributes: [.concurrent, .initiallyInactive])

延遲執(zhí)行

let delayQueue = DispatchQueue(label: "com.appcoda.delayqueue", qos: .userInitiated)

print(Date())

let additionalTime: DispatchTimeInterval = .seconds(2)

一開(kāi)始,我們像通常一樣創(chuàng)建了一個(gè) DispatchQueue,這個(gè)隊(duì)列會(huì)在下一步中被使用到。接著,我們打印了當(dāng)前時(shí)間,之后這個(gè)時(shí)間將會(huì)被用來(lái)驗(yàn)證執(zhí)行任務(wù)的延遲時(shí)間,最后我們指定了延遲時(shí)間。延遲時(shí)間通常是一個(gè) DispatchTimeInterval 類型的枚舉值(在內(nèi)部它被表示為整型值),這個(gè)值會(huì)被添加到 DispatchTime 中用于指定延遲時(shí)間。在這個(gè)示例中,設(shè)定的等待執(zhí)行時(shí)間是兩秒。這里我們使用的是seconds方法,除此之外,還有以下的方法可以使用:

  • microseconds
  • milliseconds
  • nanoseconds
delayQueue.asyncAfter(deadline: .now() + additionalTime) {
    print(Date())
}

除此之外,我們還有別的方法可以用來(lái)指定執(zhí)行時(shí)間。如果不想使用任務(wù)預(yù)定義的方法,你可以直接使用一個(gè) Double 類型的值添加到當(dāng)前時(shí)間上:

delayQueue.asyncAfter(deadline: .now() + 0.75) {
    print(Date())
}

Tips:

指定一個(gè) TimeInterval,也就是以秒為單位的整數(shù)或者分?jǐn)?shù)形式

extension DispatchTime: ExpressibleByIntegerLiteral {
    public init(integerLiteral value: Int) {
        self = DispatchTime.now() + .seconds(value)
    }
}

extension DispatchTime: ExpressibleByFloatLiteral {
    public init(floatLiteral value: Double) {
        self = DispatchTime.now() + .milliseconds(Int(value * 1000))
    }
}
DispatchQueue.main.asyncAfter(deadline: 5) { /* ... */ }

訪問(wèn)主隊(duì)列和全局隊(duì)列

操作系統(tǒng)會(huì)創(chuàng)建一個(gè)后臺(tái)隊(duì)列的集合,也被稱為全局隊(duì)列(global queue)

let globalQueue = DispatchQueue.global()

當(dāng)使用全局隊(duì)列的時(shí)候,并沒(méi)有太多的屬性可供我們進(jìn)行修改。但是,你仍然可以指定你想要使用隊(duì)列的 Quality of Service:

let globalQueue = DispatchQueue.global(qos: .userInitiated)

主隊(duì)列,通常用于更新UI

DispatchQueue.main.async {
    // Do something
}

使用DispatchWorkItem 對(duì)象

DispatchWorkItem 是一個(gè)代碼塊,它可以在任意一個(gè)隊(duì)列上被調(diào)用,因此它里面的代碼可以在后臺(tái)運(yùn)行,也可以在主線程運(yùn)行。它的使用真的很簡(jiǎn)單,就是一堆可以直接調(diào)用的代碼,而不用像之前一樣每次都寫(xiě)一個(gè)代碼塊

let workItem = DispatchWorkItem {
    // Do something
}

執(zhí)行

workItem.perform()

上行代碼在主線程調(diào)用,也可以用其它隊(duì)列執(zhí)行

let queue = DispatchQueue.global()
queue.async {
    workItem.perform()
}

快捷執(zhí)行

queue.async(execute: workItem)

當(dāng)一個(gè)任務(wù)項(xiàng)被調(diào)用后,你可以通知主隊(duì)列(或者任何其它你想要的隊(duì)列),如下所示:

workItem.notify(queue: DispatchQueue.main) {
    print("value = ", value)
}

注意點(diǎn)

  1. print("1")
    DispatchQueue.main.sync {
        print("2")
    }
    print("3")
    

    會(huì)中斷線程,Error

  2. print("1")
    DispatchQueue.main.async {
        print("2")
    }
    print("3")
    

    執(zhí)行順序1->3->2

參考: Swift.gg

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容