![](/img/trans.png)
[英]Swift async/await what it the replacement of DispatchQueue.main.async
[英]How can I convert to Swift async/await from GCD (DispatchQueue)?
我正在关注斯坦福的 CS193p 为 iOS 在线课程开发应用程序。
它使用 Grand Central Dispatch (GCD) API 进行多线程演示。 但他们注意到,
“截至 WWDC 2021,GCD 大部分已被 Swift 新的内置异步 API 所取代”。
所以我想了解讲座中的代码在更新它以使用这个新的 API 后的样子。
看完 Apple 的 WWDC 视频后,我觉得
DispatchQueue.global(qos: .userInitiated).async { }
在这个新的异步 API 中替换为Task { }
或Task(priority: .userInitiated) {}
,但我不确定DispatchQueue.main.async { }
被替换为?
所以,我的问题是:
DispatchQueue.global(qos: .userInitiated).async { }
已被替换为Task(priority: .userInitiated) {}
DispatchQueue.main.async { }
被什么替换了?请帮忙,我想学习这个新的异步等待 API。
这是讲座中的代码,使用旧的 GCD API:
DispatchQueue.global(qos: .userInitiated).async {
let imageData = try? Data(contentsOf: url)
DispatchQueue.main.async { [weak self] in
if self?.emojiArt.background == EmojiArtModel.Background.url(url) {
self?.backgroundImageFetchStatus = .idle
if imageData != nil {
self?.backgroundImage = UIImage(data: imageData!)
}
// L12 note failure if we couldn't load background image
if self?.backgroundImage == nil {
self?.backgroundImageFetchStatus = .failed(url)
}
}
}
}
整个 function (以防您需要查看更多代码):
private func fetchBackgroundImageDataIfNecessary() {
backgroundImage = nil
switch emojiArt.background {
case .url(let url):
// fetch the url
backgroundImageFetchStatus = .fetching
DispatchQueue.global(qos: .userInitiated).async {
let imageData = try? Data(contentsOf: url)
DispatchQueue.main.async { [weak self] in
if self?.emojiArt.background == EmojiArtModel.Background.url(url) {
self?.backgroundImageFetchStatus = .idle
if imageData != nil {
self?.backgroundImage = UIImage(data: imageData!)
}
// L12 note failure if we couldn't load background image
if self?.backgroundImage == nil {
self?.backgroundImageFetchStatus = .failed(url)
}
}
}
}
case .imageData(let data):
backgroundImage = UIImage(data: data)
case .blank:
break
}
}
如果你真的打算做一些缓慢和同步的事情, Task.detached
更接近于 GCD 对全局队列的分派。 如果您只使用Task(priority: ...) {... }
您将由并发系统自行决定在哪个线程上运行它。 (并且仅仅因为您指定了较低的priority
并不能保证它可能不会在主线程上运行。)
例如:
func fetchAndUpdateUI(from url: URL) {
Task.detached { // or specify a priority with `Task.detached(priority: .background)`
let data = try Data(contentsOf: url)
let image = UIImage(data: data)
await self.updateUI(with: image)
}
}
如果您想在主线程上进行 UI 更新,而不是将其分派回主队列,您只需将@MainActor
修饰符添加到更新 UI 的方法中:
@MainActor
func updateUI(with image: UIImage?) async {
imageView.image = image
}
话虽如此,这是一种非常不寻常的模式(同步执行网络请求并创建一个分离的任务以确保您不会阻塞主线程)。 我们可能会使用URLSession
的新异步data(from:delegate:)
方法来异步执行请求。
简而言之,与其为旧的 GCD 模式寻找一对一的类似物,不如尽可能使用 Apple 提供的并发 API。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.