本文假設(shè)你有一定的 GCD 和 Swift 基礎(chǔ)。
iOS 下的多線程編程技術(shù)從底層往上分別是 NSThread烂琴、NSOperation嫌佑、Grand Central Dispatch(GCD)咖耘,這三個技術(shù)越往后抽象度越高,使用也越簡單缠沈。GCD 無論在 Objective-C 時代,還是后 OC 的 Swift 時代错蝴,都是 iOS 開發(fā)者使用最多的多線程編程技術(shù)洲愤。
GCD 是使用 C 語言編寫的。多年以來顷锰,一直使用 Objective-C 的開發(fā)者們很習(xí)慣 GCD 的底層 C 語言式的代碼柬赐。這種風(fēng)格一直保留到 Swift 推出兩年后,到了 Swift 2 官紫。無論 Swift 迭代了多少回肛宋,GCD 依然保留其原始的 C-Style。終于束世,到了 2016 年酝陈,全力研發(fā) Swift 的蘋果終于想起了 GCD 這么個東西,在 WWDC 2016 推出的 Swift 3 中完全更改了 GCD 的代碼風(fēng)格毁涉。
回顧
在 Swift < 3 中后添,我們寫一個 GCD 代碼可能是這樣的:
let queue = dispatch_queue_create("Kenneth", nil)
dispatch_async(queue) {
print("Hello World")
}
我們創(chuàng)建一個串行隊列,然后指派一個輸出 Hello World 的異步任務(wù)給這個隊列薪丁,一切看上去都很自然遇西。然而唯一的缺點就是,這太不 Swift 了严嗜。
Swift < 3 中粱檀,Swift 標(biāo)準(zhǔn)庫里面的 libdispach 是一從 C 導(dǎo)入的函數(shù)的集合。這也導(dǎo)致了在 Swift < 3 中使用 GCD 非常不符合 Swift 的語法漫玄,而且這些函數(shù)名在 Swift 中看上去也很怪異茄蚯。
What's new?
我們再看看 Swift 3 中,上面的代碼是如何寫的:
let queue = DispatchQueue(label: "Kenneth")
queue.async {
print("Hello World")
}
很好睦优,這很 Swift渗常,或者說這很 OOP。
我們先簡單看一看和之前到底有何不同汗盘。
- 在之前的 GCD 中皱碘,我們寫函數(shù)的順序是,先確定異步還是同步操作隐孽,然后把隊列作為參數(shù)傳入函數(shù)癌椿,然后指派一個任務(wù)閉包健蕊。在 Swift 3 中,這個順序反了過來踢俄,我們先指定一個隊列缩功,然后再選是異步還是同步操作,這更符合面向?qū)ο蟮恼Z法特點都办。
- 變量名更符合 Swift API 的設(shè)計規(guī)范
仔細(xì)看看
命名方式
從上述的引言中嫡锌,我們可以看到在 Swift 3 中,我們熟悉的 GCD 類型名已經(jīng)發(fā)生了比較大的改變琳钉,下劃線被去掉势木,使用了大駝峰式命名法,不過好在他們還沒有脫離原來的含義槽卫,下面是一張對照表:
C | Swift |
---|---|
dispatch_object_t | DispatchObject |
dispatch_queue_t | DispatchQueue |
dispatch_group_t | DispatchGroup |
dispatch_data_t | DispatchData |
dispatch_io_t | DispatchIO |
dispatch_semaphore_t | DispatchSemaphore |
dispatch_source_t | DispatchSource |
dispatch_time_t | DispatchTime, DispatchWalltime |
C | Swift |
---|---|
dispatch_fd_t | Int32 |
dispatch_block_t | () -> () |
dispatch_queue_attr_t | DispatchQueueAttributes |
隊列
主隊列
主隊列通常被用來做我們 App 的 UI 更新操作跟压,在之前的版本,我們通過這個函數(shù)獲取主隊列:
dispatch_get_main_queue()
現(xiàn)在我們用這個屬性:
DispatchQueue.main
全局隊列
在 iOS < 8 之前歼培,我們有四種優(yōu)先級的全局隊列震蒋,他們分別是:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
在 iOS >= 8 之后,優(yōu)先級的概念被蘋果使用 QoS 替代了躲庄,Swift 3 中也一樣查剖。我們不再使用優(yōu)先級,而是使用 QoS 來描述全局隊列噪窘。簡單地說笋庄,這兩者之間的對應(yīng)關(guān)系是這樣的:
Priority | DispatchQoS |
---|---|
DISPATCH_QUEUE_PRIORITY_HIGH | .userInitiated |
DISPATCH_QUEUE_PRIORITY_DEFAULT | .default |
DISPATCH_QUEUE_PRIORITY_LOW | .utility |
DISPATCH_QUEUE_PRIORITY_BACKGROUND | .background |
在 Swift 3 中,獲取全局隊列需要使用這個方法:
DispatchQueue.global(qos: DispatchQoS.*)
我們將 QoS 傳入 global() 方法倔监,實際上就像指定它的優(yōu)先級直砂。當(dāng)然你也可以不指定,默認(rèn)就是 default浩习。
DispatchQueue.global() // 等于 DispatchQueue.global(qos: .default)
創(chuàng)建隊列
就像在前言中所舉的例子静暂,有時候我們想創(chuàng)建一個隊列,之前我們是這么寫的:
let queue = dispatch_queue_create("Kenneth", nil)
現(xiàn)在我們直接使用 init 函數(shù):
let queue = DispatchQueue(label: "Kenneth")
這么寫來創(chuàng)建一個并行隊列:
let conQueue = DispatchQueue(label: "Kenneth", attributes: .concurrent)
任務(wù)
像之前所說的一樣谱秽,在 Swift 3 中指派任務(wù)更加自然洽蛀,也更加方便。你只需要在你所指定的隊列后使用相應(yīng)的方法(.sync疟赊、.async)郊供,然后使用閉包傳入任務(wù)即可。
同步任務(wù)
使用 .sync 方法近哟,例如:
let queue = DispatchQueue(label: "Kenneth")
queue.sync {
print("Hello World")
}
Tips:請避免在主線程指定同步任務(wù)驮审,否則你的主線程可能會鎖死。
異步任務(wù)
使用 .async 方法,例如:
let queue = DispatchQueue(label: "Kenneth")
queue.async {
print("Hello World")
}
延時執(zhí)行
之前我們在 GCD 中头岔,想要指派一個任務(wù)延時執(zhí)行(比如等待一個動畫)塔拳,需要寫的代碼十分復(fù)雜鼠证。我們來看看 Swift 3 中是怎樣的:
let delay = DispatchTime.now() + 3.5
DispatchQueue.main.asyncAfter(deadline: delay) {
// 你想做啥
}
Boom峡竣!
Tips:要注意這里的單位是秒(s),如果你想更改單位的話量九,可以使用 DispatchTime 的 enum:
- .seconds(Int)
- .milliseconds(Int)
- .microseconds(Int)
- .nanoseconds(Int)
dispatch_once
dispatch_once 在 OC 時代是一個用來寫單例的很好的工具适掰,它保證任務(wù)只執(zhí)行一次。然而在 Swift 3 中荠列,這個函數(shù)被刪除了类浪。
在 Swift 中,好用又簡潔的單例請使用 static let肌似。
總結(jié)
隨著 Swift 3 的正式發(fā)布费就,GCD 新型的使用方式將會被越多的人所認(rèn)識。作為 iOS 開發(fā)者川队,我很樂于見到 GCD 新的語法更加現(xiàn)代化力细,更符合面向?qū)ο蟮乃枷耄哺阌谑褂霉潭睢O旅媸浅S玫?GCD 模板在 Swift 3 中的寫法眠蚂,供大家參考。
全局隊列異步
DispatchQueue.global().async {
//Something that wastes time
DispatchQueue.main.async {
//返回主線程
}
}
延時操作斗躏,注意這里的單位是秒
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.5) {
// 你想做啥
}
創(chuàng)建隊列同步
let queue = DispatchQueue(label: "Kenneth")
queue.sync {
print("Hello World")
}