一方面
var coins
应该在 MainThread
上更新(作为 UI 相关变量)。另一方面,cryptoService.fetchCoins()
需要在后台线程上完成。我很难连接这两个世界。在
闭包中捕获不可发送类型“MainPageViewModel”的“self”@Sendable
将不可发送类型“MainPageViewModel”的参数传递到主要参与者隔离的上下文中可能会引入数据竞争
class MainPageViewModel: ObservableObject {
@Published var coins: [Coin] = []
private let cryptoService = CryptoService()
init() {
fetchCoins()
}
private func fetchCoins() {
Task {
do {
let coins = try await cryptoService.fetchCoins()
await updateUI(with: coins)
} catch {
print("Error fetching coins: \(error)")
}
}
}
@MainActor
private func updateUI(with coins: [Coin]) {
self.coins = coins
}
}
我想做的是一些非常基本的事情。需要有一种方法可以正确地做到这一点。而且它不应该太复杂。
附注
请不要推荐组合。还必须有一种无需合并即可完成的方法。
更新。
代码库的一些 UI 部分:
@StateObject var viewModel = MainPageViewModel()
...
VStack(spacing: 12) {
ForEach(viewModel.coins) { coin in
CryptoCoinView(coin: coin)
}
}
...
当您升级到异步/等待时,您可以简单地删除组合
ObservableObject
/@Published
并仅使用.task
,例如
struct MainPage: View {
@Environment(\.cryptoService) var cryptoService
@State var coins: [Coin] = []
var body: some View {
ForEach(coins) { coin in
CryptoCoinView(coin: coin)
}
.task {
if coins.count == 0 { return }
do {
coins = try await cryptoService.fetchCoins()
} catch {
print("Error fetching coins: \(error)")
}
}
}
}
只要您的
struct CryptoService
未标记为 @MainActor
,那么 fetchCoins
就会在后台线程上运行。