孔翔鳴
摘要:Swift日漸成為iOS的主流開發(fā)語言,并有取代Objective-C之勢,本文通過實(shí)例介紹了Swift開發(fā)中使用GCD方案進(jìn)行多線程開發(fā)的方法,從而將App開發(fā)中多線程、異步運(yùn)行、定時器等實(shí)際需求的復(fù)雜性充分簡化。
關(guān)鍵詞:iOS;Swift;多線程
中圖分類號:TP393 文獻(xiàn)標(biāo)識碼:A 文章編號:1009-3044(2017)02-0024-02
iOS開發(fā)方興未艾,越來越多的開發(fā)者關(guān)注并加入iOS開發(fā)的行列。傳統(tǒng)上進(jìn)行iOS開發(fā)的唯一編程語言是Objective-C,作為上世紀(jì)八十年代出現(xiàn)的語言,Objective-C在語法和機(jī)制上與大眾熟知的C/C++、Java等現(xiàn)代編程語言大相徑庭,尤其它“怪異”的語法使得學(xué)習(xí)難度較大,許多初學(xué)者甚至是有經(jīng)驗(yàn)的開發(fā)者也經(jīng)常對此抱怨吐槽。為了解決這種不協(xié)調(diào)性,Apple公司在經(jīng)過深思熟慮之后,在2014年WWDC上發(fā)布了新一代開發(fā)語言Swift,這種全新設(shè)計的語言一經(jīng)問世便廣受開發(fā)者歡迎,短短2年的時間,Swift在TIOBE編程語言排行榜上就上升到第12位,市場份額直追Objective-C。眾多分析均認(rèn)為,根據(jù)Apple的戰(zhàn)略思路,Swift取代Objective-C成為Apple平臺的主打語言只是時間的問題。
眾所周知,受限于設(shè)備的軟硬件環(huán)境,App的開發(fā)難度要遠(yuǎn)遠(yuǎn)大于PC平臺,為了在移動設(shè)備上完成一些豐富的功能,需要使用很多復(fù)雜的技術(shù),多線程編程便是其中最為典型、最為普遍的一種,本文試圖從Swift的角度,探討其進(jìn)行多線程開發(fā)的一些思路與方法。
無論是Android還是iOS的開發(fā),都涉及一個幾乎每個App都無法逃避的問題:UI和業(yè)務(wù)邏輯的并行運(yùn)行。幾乎所有的移動操作系統(tǒng)都不約而同地采用相同的架構(gòu):界面的更新必須在UI線程中進(jìn)行,在UI以外的線程中更新界面都會造成軟件的崩潰。這使得在移動平臺上進(jìn)行多線程開發(fā)變得更為復(fù)雜。
在iOS平臺上,多線程開發(fā)基本上有三種思路:NSThread、NSOperation、GCD,三種方法各有優(yōu)缺點(diǎn),Apple官方推薦的是GCD方法。GCD 是用C語言開發(fā)并完整封裝的多線程方案,通過使用 GCD,開發(fā)者可以利用簡單的語法進(jìn)行靈活的多線程編程。在多線程編程素有“復(fù)雜必死” 的名聲,所以保持簡單就是避免錯誤的金科玉律。在 Swift 中可以無縫使用 GCD 的 API 的,尤其得益于閉包特性的加入,使用起來比之前在 Objective-C 中更加簡單方便。
關(guān)于GCD的介紹與教程有很多,初學(xué)者開始使用時往往被其復(fù)雜外表所嚇退,其實(shí)GCD的使用非常簡單,尤其是日常常見的多線程場景。GCD核心的概念是隊(duì)列,我們需要在一個線程中執(zhí)行某段代碼時,只需要將這段代碼提交給GCD的隊(duì)列,剩下的線程的創(chuàng)建、調(diào)度、運(yùn)行、銷毀等操作,均由GCD幫我們自動完成。下面是一個簡單的例子:
例1:
1 let gQueue : dispatch_queue_t =
dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 )
2 // 提交/派發(fā)到全局隊(duì)列,GCD會負(fù)責(zé)線程調(diào)度
3 dispatch_async( gQueue,
4 {
5 sleep(5)
6 //在主線程中更改UI
7 dispatch_async(dispatch_get_main_queue(),
8 {
9 self.Label.text = "5秒鐘過去的新消息"
10 })
11 }
行1聲明了一個“全局隊(duì)列”,供我們提交線程里運(yùn)行的代碼段。
行3使用dispatch_async來提交代碼段到剛聲明的隊(duì)列中,async表示這是一個異步任務(wù)。
行7-10的代碼段會由GCD自動創(chuàng)建一個新的線程,并在新線程中運(yùn)行。
行7再次提交一個代碼段,這個代碼段并不是提交到剛才聲明的全局隊(duì)列中,而是提交到“主隊(duì)列”,主隊(duì)列對應(yīng)App的主線程,即UI線程;這部分代碼段完成的工作是刷新界面,而刷新界面的操作必須在主線程中完成。
在例1中,我們接觸到GCD的幾個基本概念:隊(duì)列、提交,其中,隊(duì)列分為三種:
1)主隊(duì)列(main):使用dispatch_get_main_queue()獲取,提交到主隊(duì)列的代碼段會在主線程中運(yùn)行。
2)全局隊(duì)列(global):使用dispatch_get_global_queue()獲取,提交到全局隊(duì)列的代碼段將在新建線程中運(yùn)行。
3)用戶創(chuàng)建隊(duì)列(create):使用dispatch_queue_create()創(chuàng)建,用戶隊(duì)列和全局隊(duì)列的區(qū)別是:全局隊(duì)列只有一個,提交的代碼段(線程)是并行運(yùn)行的;用戶隊(duì)列可以創(chuàng)建多個,提交的代碼段(線程)是穿行運(yùn)行的。
dispatch_async()用于將代碼段提交到指定隊(duì)列,開發(fā)者在提交之后就無須關(guān)心其他操作了,線程的創(chuàng)建、調(diào)度等操作均由GCD負(fù)責(zé)完成。
這個例子雖然簡單,但這種結(jié)構(gòu)卻幾乎可以占到實(shí)際開發(fā)中GCD使用的50%左右,所有需要在后臺線程完成業(yè)務(wù)邏輯然后根據(jù)結(jié)果進(jìn)行界面刷新的需求,皆可通過這種結(jié)構(gòu)來完成。由此我們可以看到,通過GCD進(jìn)行多線程編程是極其簡單方便的,開發(fā)者唯一需要了解的就是GCD的一些基本概念。
在日常的開發(fā)工作中,我們經(jīng)常會遇到這樣的需求:在 xx 秒后執(zhí)行某個方法。比如切換界面 1 秒后開始播放一段動畫,或者提示框顯示 3 秒后自動消失等等。在 Objective-C 中,我們可以使用一個 NSObject 的實(shí)例方法,-performSelector:withObject:afterDelay: 來指定在若干時間后執(zhí)行某個selector。在Swift中,我們則可以利用NSTimer+GCD來完成這個工作,下面是完成這個需求的進(jìn)行封裝后的代碼段:
例2:
import Foundation
typealias Task = (cancel : Bool) -> Void
func delay(time:NSTimeInterval, task:()->()) -> Task? {
func dispatch_later(block:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(time * Double(NSEC_PER_SEC))),
dispatch_get_main_queue(),
block)
}
var closure: dispatch_block_t? = task
var result: Task?
let delayedClosure: Task = {
cancel in
if let internalClosure = closure {
if (cancel == false) {
dispatch_async(dispatch_get_main_queue(), internalClosure);
}
}
closure = nil
result = nil
}
result = delayedClosure
dispatch_later {
if let delayedClosure = result {
delayedClosure(cancel: false)
}
}
return result;
}
有了以上的封裝代碼,當(dāng)我們需要完成諸如“延遲3秒后做點(diǎn)什么事兒”的任務(wù)時,只需要簡單地進(jìn)行以下調(diào)用:
delay(2) { print("3秒后顯示信息") }
這個例子雖然有點(diǎn)長,但是原理和結(jié)構(gòu)與例1基本相同,只不過增加了dispatch_later()和dispatch_time()兩個新的調(diào)用,理解了例1之后,例2也是很容易理解的。
綜上所述,在進(jìn)行Swift開發(fā)時,當(dāng)遇到多線程、異步運(yùn)行、定時器之類的需求時,我們都可以利用GCD這個利器來簡化我們的工作,同時兼顧簡單、快捷和優(yōu)雅。當(dāng)然,GCD的功能并不僅限于以上的介紹,熟練掌握GCD的應(yīng)用,是成熟的iOS程序員必備的技能,每一個Swift開發(fā)者都應(yīng)該將GCD放入自己的工具箱。
參考文獻(xiàn):
[1] Apple Swift官方文檔: https://developer.apple.com/swift/
[2] Grand Central Dispatch In-Depth: https://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1
[3] 歐陽堅(jiān). Swift開發(fā)實(shí)戰(zhàn)權(quán)威指南[M]. 北京: 清華大學(xué)出版社, 2015.