如何在 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 函数和存储过程

如何在 Swift 5.5 中使用 List 中的新绑定?

sql 如何在MySQL 5.5中将utf8mb4表转换为utf8

如何使用 SwiftUI 按按钮移动到另一个视图 - swift 5.5

Swift 5.5 并发:如何序列化异步任务以用 maxConcurrentOperationCount = 1 替换 OperationQueue?