On the one hand var coins should be updated on MainThread (as a UI related variable). On the other hand cryptoService.fetchCoins() needs to be done on a background thread. I'm having hard times to connect these two worlds.
In the code below I did my best, but still have some compile warnings which I don't understand. Two warnings on two lines of the "do" block:
Capture of 'self' with non-sendable type 'MainPageViewModel' in a
@Sendableclosure
Passing argument of non-sendable type 'MainPageViewModel' into main actor-isolated context may introduce data races
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
}
}
What I'm trying to do is some very basic things. There need to be a way to do it correctly. And it shouldn't be too sophisticated way.
P.S.
Please, don't recommend Combine. There also must be a way to do it without Combine.
Update.
Some UI part of the codebase:
@StateObject var viewModel = MainPageViewModel()
...
VStack(spacing: 12) {
ForEach(viewModel.coins) { coin in
CryptoCoinView(coin: coin)
}
}
...
Update.
I've removed the mention of runtime warnings from the post, because it appeared they were related to completely another part of my application Sorry for that.
As for the compilation warnings...
Looks like in the default settings of a Xcode project there are no any of those warnings. The reason why I'm seeing them, is because in "Build Settings" of my project I choose "Complete" to the "Strict Concurrency Checking" setting (default was "Minimal").
So the main question of the post is still pretty much relevant. Why do we see those warnings in Complete Concurrency Checking mode? Does this mean that in the future versions of Swift we'll see the warnings in this situation even in default mode? Or will they eventually even become compilation errors?
When you upgrade to async/await you can simply remove the Combine
ObservableObject/@Publishedand just use.task, e.g.As long as your
struct CryptoServiceis not marked@MainActorthenfetchCoinswill run on a background thread.