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.反向DNS
com.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 中被稱(chēng)為 Quality of Service(QoS)
優(yōu)先級(jí)從大到小
userInteractive
userInitiated
default
utility
background
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
類(lèi)的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
類(lèi)型的枚舉值(在內(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 類(lèi)型的值添加到當(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ì)列的集合五续,也被稱(chēng)為全局隊(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)
-
print("1") DispatchQueue.main.sync { print("2") } print("3")
會(huì)中斷線程,Error
-
print("1") DispatchQueue.main.async { print("2") } print("3")
執(zhí)行順序1->3->2
參考: Swift.gg