如何在 Swift 5.5 中将 async/await 与 SwiftUI 一起使用?
Posted
技术标签:
【中文标题】如何在 Swift 5.5 中将 async/await 与 SwiftUI 一起使用?【英文标题】:How can I use async/await with SwiftUI in Swift 5.5? 【发布时间】:2021-07-26 05:24:26 【问题描述】:我一直在测试 Swift 5.5 版本中预览的 async/await 功能,但我无法从异步函数收集结果并使用 SwiftUI 显示它们。这是我的代码:
import SwiftUI
struct AsyncTestView: View
@State var text: String?
// Async function
func asyncGetText() async -> String
Thread.sleep(forTimeInterval: 10)
return "My text"
// Stores the result of async function
func fetchText() async
let text = await asyncGetText()
DispatchQueue.main.async
self.text = text
var body: some View
Text(text ?? "Loading")
.onAppear(perform: fetchText)
这会导致以下错误:
在不支持并发的函数中调用'async' 将 'async' 添加到函数 'fetchText()' 以使其异步
将async
添加到fetchText()
函数会导致.onAppear()
函数出现以下错误:
从'() async -> ()' 类型的'async' 函数到'() -> Void' 类型的同步函数的转换无效
在this article 中,他们使用@asyncHandler
标签来注释fetchText
函数,但是这会导致警告:'@asyncHandler' has been removed from the language'
。
【问题讨论】:
Xcode 12.5 是 Swift 5.4 那么我们到底在说什么?您是否安装了不同的工具链? 是的,我下载了 Swift 5.5 Development Snapshot 工具链 【参考方案1】:我是你引用的the article的作者。
正如Discover concurrency in SwiftUI 中所讨论的,视图可以利用新的.task
和.refreshable
修饰符来异步获取数据。
所以你现在有以下选项来调用你的异步代码:
func someSyncMethod()
doSomeSyncWork()
Task
await methodThatIsAsync()
List
.task
await methodThatIsAsync()
List
.refreshable
await methodThatIsAsync()
如果您使用单独的视图模型,请确保将其标记为 @MainActor
以确保在主要参与者上执行属性更新。
我更新了我文章的代码:https://github.com/peterfriese/Swift-Async-Await-Experiments
【讨论】:
我完全经历过真正做到这种事情的真实代码(想想相互依赖的连续在线数据库调用)。组合框架最终救了我,但 async/await 真的会救我。事实是,95% 的程序员似乎甚至不理解异步的含义(因此我的 programmingios.net/what-asynchronous-means),而使用 async/await,他们就不必理解了! @matt 我来这里才一年左右,实际上有四分之一的问题是因为完成处理程序。也期待 async/await!【参考方案2】:根据 WWDC 会话 Meet async/await in Swift WWDC 中的新信息,现在在 23m:28s 使用:
async
someState = await someAsyncFunction()
会议截图。
【讨论】:
如何在 iOS14 的 onAppear 中调用 async fun? 我相信你不会。这是iOS15+ api。但奇怪的是,目前 Xcode Beta 1 让我部署到我的 iPhone 上,它是 iOS14.5。但是一旦调用了一些 Async/Await 代码,它就会崩溃。 我不记得我在哪里读到它可以通过演员。 我之前的帖子错了。 Apple 开发人员承诺解决问题以在 iOS 14 及更低版本上运行此功能。等待下一个 Xcode 测试版。 承诺调查。不承诺改变它。这很难。看看这个:forums.swift.org/t/…【参考方案3】:我同意@peter-friese 的回答,但会为那些阅读本文的人添加从同步到异步桥接时的语法变化:
新语法:
Task
someState = await someAsyncFunction()
替换此语法:
async
someState = await someAsyncFunction()
...Task()
初始化器可以接受优先级参数:
Task(priority: .userInitiated)
someState = await someAsyncFunction()
【讨论】:
【参考方案4】:import SwiftUI
struct AsyncTestView: View
@State var text = “Loading”
// Async function
func asyncGetText() async -> String
Thread.sleep(forTimeInterval: 10) // Maybe should be Task.sleep
return "My text"
var body: some View
Text(text)
.task
text = await asyncGetText()
【讨论】:
以上是关于如何在 Swift 5.5 中将 async/await 与 SwiftUI 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Laravel 5.5 中将数据插入表格并获取电子邮件通知?
如何在 laravel 5.5 迁移中将 DB::unprepared() 用于 mysql 函数和存储过程
sql 如何在MySQL 5.5中将utf8mb4表转换为utf8
如何使用 SwiftUI 按按钮移动到另一个视图 - swift 5.5
Swift 5.5 并发:如何序列化异步任务以用 maxConcurrentOperationCount = 1 替换 OperationQueue?