赞
踩
在Swift5.5以前或Object-C时代iOS开发要实现并发代码,一般要自己使用多线程,如DispatchGroup,DispatchSemaphore等等,且都是命令式代码,并不能使用诸如await等响应式代码的方式,异步转同步直观的获取异步资源。Swift5.5 Concurrency就解决了这个问题,我认为这是一个非常棒的设计,虽然其他语言老早就有类似的语法,但不得不再赞一次。但是令人遗憾的是,Swift5.5 Concurrency编程是建立在Xcode13以及iOS15之上的,也就是说旧项目的支持依然无法使用。以下是介绍Swift5.5 Concurrency的写法,我也会使用旧有的线程方式作为对比。
这里我以下载网络图为例子。
首先要说的是 await 必须与 async 搭配使用
func downloadImage(url: String) async -> UIImage? {
return await loadImage(url: url)
}
如果在viewDidLoad 等不能 async的场景怎么办?(无需纠结为什么不行,直接编译会报错,个人理解是Concurrency也是多线程的方式实现,viewDidLoad等方法直接操作的UI必然在主线程,肯定是不能async的)
那就要用Task包裹,如在viewDidLoad获取一张网络图并显示。
使用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
}
}
}
当我们想下载多张网图,且等全部图片下载完再做事情是这样的:
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) } //等待上面执行完,再做下面的事情 await taskGroup.waitForAll() //取消全部 // taskGroup.cancelAll() print("wait finished and do") results.append(await loadImage()!) } return results }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。