前言
在Swift5.5以前或Object-C時代iOS開發(fā)要實現(xiàn)并發(fā)代碼,一般要自己使用多線程,如DispatchGroup,DispatchSemaphore等等绩郎,且都是命令式代碼,并不能使用諸如await等響應(yīng)式代碼的方式,異步轉(zhuǎn)同步直觀的獲取異步資源外里。Swift5.5 Concurrency就解決了這個問題,我認為這是一個非常棒的設(shè)計特石,雖然其他語言老早就有類似的語法盅蝗,但不得不再贊一次。但是令人遺憾的是姆蘸,Swift5.5 Concurrency編程是建立在Xcode13以及iOS15之上的墩莫,也就是說舊項目的支持依然無法使用。以下是介紹Swift5.5 Concurrency的寫法逞敷,我也會使用舊有的線程方式作為對比狂秦。
參考文獻
基本語法
這里我以下載網(wǎng)絡(luò)圖為例子。
首先要說的是 await 必須與 async 搭配使用
func downloadImage(url: String) async -> UIImage? {
return await loadImage(url: url)
}
如果在viewDidLoad 等不能 async的場景怎么辦推捐?(無需糾結(jié)為什么不行裂问,直接編譯會報錯,個人理解是Concurrency也是多線程的方式實現(xiàn)牛柒,viewDidLoad等方法直接操作的UI必然在主線程堪簿,肯定是不能async的)
那就要用Task包裹,如在viewDidLoad獲取一張網(wǎng)絡(luò)圖并顯示。
使用await可以這么寫
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.imageView)
Task {
let image = await self.loadImage()
DispatchQueue.main.async {
self.imageView.image = image
}
}
}
舊的寫法可能是:
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.imageView)
self.asyncLoadImage(url: "http://image.jerryfans.com/iterm2_bg_image.jpg") { [weak self] image in
guard let self = self else { return }
guard let img = image else { return }
DispatchQueue.main.async {
self.imageView.image = img
}
}
}
當(dāng)我們想下載多張網(wǎng)圖焰络,且等全部圖片下載完再做事情是這樣的:
Concurrency方式:
//方式1
func multiImageLoad() async -> [UIImage]? {
var results: [UIImage] = []
await withTaskGroup(of: UIImage.self) { taskGroup in
for ele in origins.enumerated() {
taskGroup.addTask {
return await self.loadImage(url: origins[ele.offset])!
}
}
for await result in taskGroup {
results.append(result)
}
}
return results
}
//方式2
func multiImageLoad() async -> [UIImage]? {
var results: [UIImage] = []
for ele in origins.enumerated() {
results.append(await self.loadImage(url: origins[ele.offset])!)
}
return results
}
然后使用一般是這樣:
Task {
guard let images = await multiImageLoad() else { return }
DispatchQueue.main.async {
print(images)
//do your things
}
}
舊方式之一:
func multiImageLoad_old() {
let group = DispatchGroup()
group.enter()
// load img 1
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
group.leave()
}
group.enter()
// load img 2
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
group.leave()
}
group.notify(queue: .main) {
//do your things
}
}
其他語法
如等待兩三個接口完成戴甩,再下一個接口
func multiWaitFinishLoad() async -> [UIImage]? {
var results: [UIImage] = []
await withTaskGroup(of: UIImage.self) { taskGroup in
for ele in origins.enumerated() {
taskGroup.addTask {
print("begin ele \(ele.offset)")
return await self.loadImage(url: origins[ele.offset])!
}
}
for await result in taskGroup {
results.append(result)
}
//等待上面執(zhí)行完,再做下面的事情
await taskGroup.waitForAll()
//取消全部
// taskGroup.cancelAll()
print("wait finished and do")
results.append(await loadImage()!)
}
return results
}