【问题标题】:How can I use async/await with SwiftUI in Swift 5.5?如何在 Swift 5.5 中将 async/await 与 SwiftUI 一起使用?
【发布时间】: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 工具链

标签: swift async-await swiftui swift5


【解决方案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()
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2022-01-03
      • 2014-03-13
      • 2017-07-02
      • 1970-01-01
      • 1970-01-01
      • 2021-10-02
      • 2017-11-05
      • 2019-04-15
      • 2014-06-19
      相关资源
      最近更新 更多