跳到主要内容

如何在 Combine 框架中使用 Swift 中 async/await 函数

· 阅读需 3 分钟
GoSwiftUI
goswiftui.com

了解如何在基于组合的 API 中调用 async/await 代码

在 Swift 中处理异步代码时,我们可能必须找到组合实现不同异步模式的方法,例如将 Combine 框架与 Swift 的 async/await API 一起使用。

在本文中,我们将了解如何在 Combine API 中调用带有 async 标记的函数。

让我们看看下面的异步函数,它使用 async/await 模式从服务器加载用户。

func loadUser() async throws -> User {
// Load user from server
return user // or throw error
}

要使用 Combine 实现相同的行为,它的 Future 发布者就派上用场了。未来使用带有 Future.Promise 的闭包进行初始化。在完成一些异步工作之后,我们用一个成功或失败的 Result 调用该闭包。然后,Combine 会自动将结果映射到适当的发布者事件中。

让我们看看如何使用 Future 发布者实现上面的 async 函数:

func loadUser() -> Future<User, Error> {
return Future() { promise in
// Load user from server.
promise(.success(user)) // or promise(.failure(error))
}
}

但是由于我们已经有一个加载用户的实现,我们希望避免重复编写相同的逻辑。

因此,让我们尝试找到一个更通用的解决方法,它允许我们将 async func 转换为Future发布者。

extension Future where Failure == Error {
convenience init(asyncFunc: @escaping () async throws -> Output) {
self.init { promise in
Task {
do {
let result = try await asyncFunc()
promise(.success(result))
} catch {
promise(.failure(error))
}
}
}
}
}

在上面的代码中,我们在初始化中扩展了 Future 类型,它允许我们用一个异步闭包来初始化一个实例。应用于我们的示例:

func loadUser() -> Future<Int, Error> {
return Future(asyncFunc: {
try await loadUser()
})
}

对于异常的情况,我们可以添加另一个扩展:

extension Future where Failure == Never {

convenience init(asyncFunc: @escaping () async -> Output) {
self.init { promise in
Task {
let result = await asyncFunc()
promise(.success(result))
}
}
}
}

有了像这样的通用解决方案,我们现在可以在任何 async 函数上使用它来将其桥接到 Combine 的 Future。